2 Copyright (C) 1999-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #include <sys/resource.h>
33 #include <gtkmm/messagedialog.h>
34 #include <gtkmm/accelmap.h>
36 #include <pbd/error.h>
37 #include <pbd/basename.h>
38 #include <pbd/compose.h>
39 #include <pbd/pathscanner.h>
40 #include <pbd/failed_constructor.h>
41 #include <pbd/enumwriter.h>
42 #include <pbd/stacktrace.h>
43 #include <gtkmm2ext/gtk_ui.h>
44 #include <gtkmm2ext/utils.h>
45 #include <gtkmm2ext/click_box.h>
46 #include <gtkmm2ext/fastmeter.h>
47 #include <gtkmm2ext/stop_signal.h>
48 #include <gtkmm2ext/popup.h>
49 #include <gtkmm2ext/window_title.h>
51 #include <midi++/port.h>
52 #include <midi++/mmc.h>
54 #include <ardour/ardour.h>
55 #include <ardour/profile.h>
56 #include <ardour/session_route.h>
57 #include <ardour/port.h>
58 #include <ardour/audioengine.h>
59 #include <ardour/playlist.h>
60 #include <ardour/utils.h>
61 #include <ardour/audio_diskstream.h>
62 #include <ardour/audiofilesource.h>
63 #include <ardour/recent_sessions.h>
64 #include <ardour/port.h>
65 #include <ardour/audio_track.h>
67 typedef uint64_t microseconds_t;
70 #include "ardour_ui.h"
71 #include "public_editor.h"
72 #include "audio_clock.h"
77 #include "add_route_dialog.h"
78 #include "new_session_dialog.h"
82 #include "gui_thread.h"
83 #include "theme_manager.h"
84 #include "engine_dialog.h"
85 #include "gain_meter.h"
86 #include "route_time_axis.h"
90 using namespace ARDOUR;
92 using namespace Gtkmm2ext;
96 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
97 UIConfiguration *ARDOUR_UI::ui_config = 0;
99 sigc::signal<void,bool> ARDOUR_UI::Blink;
100 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
101 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
102 sigc::signal<void,nframes_t, bool, nframes_t> ARDOUR_UI::Clock;
104 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[])
106 : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp),
108 primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true),
109 secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true),
110 preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
111 postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
115 preroll_button (_("pre\nroll")),
116 postroll_button (_("post\nroll")),
120 big_clock (X_("bigclock"), false, "BigClockNonRecording", true, false, true),
124 roll_controllable ("transport roll", *this, TransportControllable::Roll),
125 stop_controllable ("transport stop", *this, TransportControllable::Stop),
126 goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart),
127 goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd),
128 auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop),
129 play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection),
130 rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable),
131 shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
132 shuttle_controller_binding_proxy (shuttle_controllable),
134 roll_button (roll_controllable),
135 stop_button (stop_controllable),
136 goto_start_button (goto_start_controllable),
137 goto_end_button (goto_end_controllable),
138 auto_loop_button (auto_loop_controllable),
139 play_selection_button (play_selection_controllable),
140 rec_button (rec_controllable),
142 shuttle_units_button (_("% ")),
144 punch_in_button (_("Punch In")),
145 punch_out_button (_("Punch Out")),
146 auto_return_button (_("Auto Return")),
147 auto_play_button (_("Auto Play")),
148 auto_input_button (_("Auto Input")),
149 click_button (_("Click")),
150 time_master_button (_("time\nmaster")),
152 auditioning_alert_button (_("AUDITION")),
153 solo_alert_button (_("SOLO")),
155 error_log_button (_("Errors"))
157 using namespace Gtk::Menu_Helpers;
162 _auto_display_errors = false;
168 if (ARDOUR_COMMAND_LINE::session_name.length()) {
169 /* only show this if we're not going to post the new session dialog */
173 if (theArdourUI == 0) {
177 ui_config = new UIConfiguration();
178 theme_manager = new ThemeManager();
184 _session_is_new = false;
185 big_clock_window = 0;
186 session_selector_window = 0;
187 new_session_dialog = 0;
188 last_key_press_time = 0;
189 connection_editor = 0;
190 add_route_dialog = 0;
195 open_session_selector = 0;
196 have_configure_timeout = false;
197 have_disk_speed_dialog_displayed = false;
198 _will_create_new_session_automatically = false;
199 session_loaded = false;
200 last_speed_displayed = -1.0f;
201 ignore_dual_punch = false;
203 last_configure_time= 0;
205 shuttle_grabbed = false;
207 shuttle_max_speed = 8.0f;
209 shuttle_style_menu = 0;
210 shuttle_unit_menu = 0;
212 // We do not have jack linked in yet so;
214 last_shuttle_request = last_peak_grab = 0; // get_microseconds();
216 ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
217 ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
219 /* handle dialog requests */
221 ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
223 /* handle pending state with a dialog */
225 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
227 /* handle sr mismatch with a dialog */
229 ARDOUR::Session::AskAboutSampleRateMismatch.connect (mem_fun(*this, &ARDOUR_UI::sr_mismatch_dialog));
231 /* lets get this party started */
234 if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization)) {
235 throw failed_constructor ();
238 setup_gtk_ardour_enums ();
239 Config->set_current_owner (ConfigVariableBase::Interface);
242 GainMeter::setup_slider_pix ();
243 RouteTimeAxisView::setup_slider_pix ();
245 } catch (failed_constructor& err) {
246 error << _("could not initialize Ardour.") << endmsg;
251 /* we like keyboards */
253 keyboard = new Keyboard;
257 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
258 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
264 ARDOUR_UI::create_engine ()
266 // this gets called every time by new_session()
272 loading_message (_("Starting audio engine"));
275 engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name);
282 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
283 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
284 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
285 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
293 ARDOUR_UI::post_engine ()
295 /* Things to be done once we create the AudioEngine
298 check_memory_locking();
300 ActionManager::init ();
303 if (setup_windows ()) {
304 throw failed_constructor ();
307 /* this is the first point at which all the keybindings are available */
309 if (ARDOUR_COMMAND_LINE::show_key_actions) {
310 vector<string> names;
311 vector<string> paths;
313 vector<AccelKey> bindings;
315 ActionManager::get_all_actions (names, paths, keys, bindings);
317 vector<string>::iterator n;
318 vector<string>::iterator k;
319 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
320 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
326 blink_timeout_tag = -1;
328 /* the global configuration object is now valid */
332 /* this being a GUI and all, we want peakfiles */
334 AudioFileSource::set_build_peakfiles (true);
335 AudioFileSource::set_build_missing_peakfiles (true);
337 /* set default clock modes */
339 if (Profile->get_sae()) {
340 primary_clock.set_mode (AudioClock::MinSec);
342 primary_clock.set_mode (AudioClock::SMPTE);
344 secondary_clock.set_mode (AudioClock::BBT);
346 /* start the time-of-day-clock */
349 /* OS X provides an always visible wallclock, so don't be stupid */
350 update_wall_clock ();
351 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
354 update_disk_space ();
356 update_sample_rate (engine->frame_rate());
358 platform_specific ();
360 /* now start and maybe save state */
362 if (do_engine_start () == 0) {
363 if (session && _session_is_new) {
364 /* we need to retain initial visual
365 settings for a new session
367 session->save_state ("");
372 ARDOUR_UI::~ARDOUR_UI ()
374 save_ardour_state ();
388 if (add_route_dialog) {
389 delete add_route_dialog;
392 if (new_session_dialog) {
393 delete new_session_dialog;
398 ARDOUR_UI::pop_back_splash ()
400 if (Splash::instance()) {
401 // Splash::instance()->pop_back();
402 Splash::instance()->hide ();
407 ARDOUR_UI::configure_timeout ()
409 if (last_configure_time == 0) {
410 /* no configure events yet */
414 /* force a gap of 0.5 seconds since the last configure event
417 if (get_microseconds() - last_configure_time < 500000) {
420 have_configure_timeout = false;
421 save_ardour_state ();
427 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
429 if (have_configure_timeout) {
430 last_configure_time = get_microseconds();
432 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
433 have_configure_timeout = true;
440 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
442 const XMLProperty* prop;
444 if ((prop = node.property ("roll")) != 0) {
445 roll_controllable.set_id (prop->value());
447 if ((prop = node.property ("stop")) != 0) {
448 stop_controllable.set_id (prop->value());
450 if ((prop = node.property ("goto_start")) != 0) {
451 goto_start_controllable.set_id (prop->value());
453 if ((prop = node.property ("goto_end")) != 0) {
454 goto_end_controllable.set_id (prop->value());
456 if ((prop = node.property ("auto_loop")) != 0) {
457 auto_loop_controllable.set_id (prop->value());
459 if ((prop = node.property ("play_selection")) != 0) {
460 play_selection_controllable.set_id (prop->value());
462 if ((prop = node.property ("rec")) != 0) {
463 rec_controllable.set_id (prop->value());
465 if ((prop = node.property ("shuttle")) != 0) {
466 shuttle_controllable.set_id (prop->value());
471 ARDOUR_UI::get_transport_controllable_state ()
473 XMLNode* node = new XMLNode(X_("TransportControllables"));
476 roll_controllable.id().print (buf, sizeof (buf));
477 node->add_property (X_("roll"), buf);
478 stop_controllable.id().print (buf, sizeof (buf));
479 node->add_property (X_("stop"), buf);
480 goto_start_controllable.id().print (buf, sizeof (buf));
481 node->add_property (X_("goto_start"), buf);
482 goto_end_controllable.id().print (buf, sizeof (buf));
483 node->add_property (X_("goto_end"), buf);
484 auto_loop_controllable.id().print (buf, sizeof (buf));
485 node->add_property (X_("auto_loop"), buf);
486 play_selection_controllable.id().print (buf, sizeof (buf));
487 node->add_property (X_("play_selection"), buf);
488 rec_controllable.id().print (buf, sizeof (buf));
489 node->add_property (X_("rec"), buf);
490 shuttle_controllable.id().print (buf, sizeof (buf));
491 node->add_property (X_("shuttle"), buf);
497 ARDOUR_UI::save_ardour_state ()
499 if (!keyboard || !mixer || !editor) {
503 /* XXX this is all a bit dubious. add_extra_xml() uses
504 a different lifetime model from add_instant_xml().
507 XMLNode* node = new XMLNode (keyboard->get_state());
508 Config->add_extra_xml (*node);
509 Config->add_extra_xml (get_transport_controllable_state());
510 if (new_session_dialog) {
511 if (new_session_dialog->engine_control.was_used()) {
512 Config->add_extra_xml (new_session_dialog->engine_control.get_state());
515 Config->save_state();
516 ui_config->save_state ();
518 XMLNode enode(static_cast<Stateful*>(editor)->get_state());
519 XMLNode mnode(mixer->get_state());
522 session->add_instant_xml (enode, session->path());
523 session->add_instant_xml (mnode, session->path());
525 Config->add_instant_xml (enode, get_user_ardour_path());
526 Config->add_instant_xml (mnode, get_user_ardour_path());
529 Keyboard::save_keybindings ();
533 ARDOUR_UI::autosave_session ()
535 if (!Config->get_periodic_safety_backups())
539 session->maybe_write_autosave();
546 ARDOUR_UI::update_autosave ()
548 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
550 if (session->dirty()) {
551 if (_autosave_connection.connected()) {
552 _autosave_connection.disconnect();
555 _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session),
556 Config->get_periodic_safety_backup_interval() * 1000);
559 if (_autosave_connection.connected()) {
560 _autosave_connection.disconnect();
566 ARDOUR_UI::backend_audio_error (bool we_set_params, Gtk::Window* toplevel)
570 title = _("Ardour could not start JACK");
572 title = _("Ardour could not connect to JACK.");
575 MessageDialog win (title,
581 win.set_secondary_text(_("There are several possible reasons:\n\
583 1) You requested audio parameters that are not supported..\n\
584 2) JACK is running as another user.\n\
586 Please consider the possibilities, and perhaps try different parameters."));
588 win.set_secondary_text(_("There are several possible reasons:\n\
590 1) JACK is not running.\n\
591 2) JACK is running as another user, perhaps root.\n\
592 3) There is already another client called \"ardour\".\n\
594 Please consider the possibilities, and perhaps (re)start JACK."));
598 win.set_transient_for (*toplevel);
602 win.add_button (Stock::OK, RESPONSE_CLOSE);
604 win.add_button (Stock::QUIT, RESPONSE_CLOSE);
607 win.set_default_response (RESPONSE_CLOSE);
610 win.set_position (Gtk::WIN_POS_CENTER);
613 /* we just don't care about the result, but we want to block */
619 ARDOUR_UI::startup ()
623 new_session_dialog = new NewSessionDialog();
625 bool backend_audio_is_running = EngineControl::engine_running();
626 XMLNode* audio_setup = Config->extra_xml ("AudioSetup");
629 new_session_dialog->engine_control.set_state (*audio_setup);
632 if (!get_session_parameters (backend_audio_is_running, ARDOUR_COMMAND_LINE::new_session)) {
636 BootMessage (_("Ardour is ready for use"));
641 ARDOUR_UI::no_memory_warning ()
643 XMLNode node (X_("no-memory-warning"));
644 Config->add_instant_xml (node, get_user_ardour_path());
648 ARDOUR_UI::check_memory_locking ()
651 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
655 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path());
657 if (engine->is_realtime() && memory_warning_node == 0) {
659 struct rlimit limits;
661 long pages, page_size;
663 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) {
666 ram = (int64_t) pages * (int64_t) page_size;
669 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
673 if (limits.rlim_cur != RLIM_INFINITY) {
675 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
678 MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. "
679 "This might cause Ardour to run out of memory before your system "
680 "runs out of memory. \n\n"
681 "You can view the memory limit with 'ulimit -l', "
682 "and it is normally controlled by /etc/security/limits.conf"));
684 VBox* vbox = msg.get_vbox();
686 CheckButton cb (_("Do not show this window again"));
688 cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning));
690 hbox.pack_start (cb, true, false);
691 vbox->pack_start (hbox);
709 if (session->transport_rolling()) {
710 session->request_stop ();
714 if (session->dirty()) {
715 switch (ask_about_saving_session(_("quit"))) {
720 /* use the default name */
721 if (save_state_canfail ("")) {
722 /* failed - don't quit */
723 MessageDialog msg (*editor,
725 Ardour was unable to save your session.\n\n\
726 If you still wish to quit, please use the\n\n\
727 \"Just quit\" option."));
738 session->set_deletion_in_progress ();
742 save_ardour_state ();
747 ARDOUR_UI::ask_about_saving_session (const string & what)
749 ArdourDialog window (_("ardour: save session?"));
750 Gtk::HBox dhbox; // the hbox for the image and text
751 Gtk::Label prompt_label;
752 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
756 msg = string_compose(_("Don't %1"), what);
757 window.add_button (msg, RESPONSE_REJECT);
758 msg = string_compose(_("Just %1"), what);
759 window.add_button (msg, RESPONSE_APPLY);
760 msg = string_compose(_("Save and %1"), what);
761 window.add_button (msg, RESPONSE_ACCEPT);
763 window.set_default_response (RESPONSE_ACCEPT);
765 Gtk::Button noquit_button (msg);
766 noquit_button.set_name ("EditorGTKButton");
771 if (session->snap_name() == session->name()) {
774 type = _("snapshot");
776 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?"),
777 type, session->snap_name());
779 prompt_label.set_text (prompt);
780 prompt_label.set_name (X_("PrompterLabel"));
781 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
783 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP)
785 dhbox.set_homogeneous (false);
786 dhbox.pack_start (*dimage, false, false, 5);
787 dhbox.pack_start (prompt_label, true, false, 5);
788 window.get_vbox()->pack_start (dhbox);
790 window.set_name (_("Prompter"));
791 window.set_position (Gtk::WIN_POS_MOUSE);
792 window.set_modal (true);
793 window.set_resizable (false);
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::check_audioengine ()
1130 if (!engine->connected()) {
1131 MessageDialog msg (_("Ardour is not connected to JACK\n"
1132 "You cannot open or close sessions in this condition"));
1144 ARDOUR_UI::open_session ()
1146 if (!check_audioengine()) {
1150 /* popup selector window */
1152 if (open_session_selector == 0) {
1154 /* ardour sessions are folders */
1156 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1157 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1158 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1159 open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
1161 FileFilter session_filter;
1162 session_filter.add_pattern ("*.ardour");
1163 session_filter.set_name (_("Ardour sessions"));
1164 open_session_selector->add_filter (session_filter);
1165 open_session_selector->set_filter (session_filter);
1168 int response = open_session_selector->run();
1169 open_session_selector->hide ();
1172 case RESPONSE_ACCEPT:
1175 open_session_selector->hide();
1179 open_session_selector->hide();
1180 string session_path = open_session_selector->get_filename();
1184 if (session_path.length() > 0) {
1185 if (Session::find_session (session_path, path, name, isnew) == 0) {
1186 _session_is_new = isnew;
1187 load_session (path, name);
1194 ARDOUR_UI::session_add_midi_track ()
1196 cerr << _("Patience is a virtue.\n");
1200 ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many)
1202 list<boost::shared_ptr<AudioTrack> > tracks;
1203 Session::RouteList routes;
1206 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1212 tracks = session->new_audio_track (input_channels, output_channels, mode, how_many);
1214 if (tracks.size() != how_many) {
1215 if (how_many == 1) {
1216 error << _("could not create a new audio track") << endmsg;
1218 error << string_compose (_("could only create %1 of %2 new audio %3"),
1219 tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg;
1225 routes = session->new_audio_route (input_channels, output_channels, how_many);
1227 if (routes.size() != how_many) {
1228 if (how_many == 1) {
1229 error << _("could not create a new audio track") << endmsg;
1231 error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg;
1237 if (need_control_room_outs) {
1243 route->set_stereo_control_outs (control_lr_channels);
1244 route->control_outs()->set_stereo_pan (pans, this);
1246 #endif /* CONTROLOUTS */
1250 MessageDialog msg (*editor,
1251 _("There are insufficient JACK ports available\n\
1252 to create a new track or bus.\n\
1253 You should save Ardour, exit and\n\
1254 restart JACK with more ports."));
1261 ARDOUR_UI::do_transport_locate (nframes_t new_position)
1263 nframes_t _preroll = 0;
1266 // XXX CONFIG_CHANGE FIX - requires AnyTime handling
1267 // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll());
1269 if (new_position > _preroll) {
1270 new_position -= _preroll;
1275 session->request_locate (new_position);
1280 ARDOUR_UI::transport_goto_start ()
1283 session->goto_start();
1286 /* force displayed area in editor to start no matter
1287 what "follow playhead" setting is.
1291 editor->reset_x_origin (session->current_start_frame());
1297 ARDOUR_UI::transport_goto_zero ()
1300 session->request_locate (0);
1303 /* force displayed area in editor to start no matter
1304 what "follow playhead" setting is.
1308 editor->reset_x_origin (0);
1314 ARDOUR_UI::transport_goto_wallclock ()
1316 if (session && editor) {
1323 localtime_r (&now, &tmnow);
1325 frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
1326 frames += tmnow.tm_min * (60 * session->frame_rate());
1327 frames += tmnow.tm_sec * session->frame_rate();
1329 session->request_locate (frames);
1331 /* force displayed area in editor to start no matter
1332 what "follow playhead" setting is.
1336 editor->reset_x_origin (frames - (editor->current_page_frames()/2));
1342 ARDOUR_UI::transport_goto_end ()
1345 nframes_t frame = session->current_end_frame();
1346 session->request_locate (frame);
1348 /* force displayed area in editor to start no matter
1349 what "follow playhead" setting is.
1353 editor->reset_x_origin (frame);
1359 ARDOUR_UI::transport_stop ()
1365 if (session->is_auditioning()) {
1366 session->cancel_audition ();
1370 if (session->get_play_loop ()) {
1371 session->request_play_loop (false);
1374 session->request_stop ();
1378 ARDOUR_UI::transport_stop_and_forget_capture ()
1381 session->request_stop (true);
1386 ARDOUR_UI::remove_last_capture()
1389 editor->remove_last_capture();
1394 ARDOUR_UI::transport_record (bool roll)
1398 switch (session->record_status()) {
1399 case Session::Disabled:
1400 if (session->ntracks() == 0) {
1401 MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."));
1405 session->maybe_enable_record ();
1410 case Session::Recording:
1412 session->request_stop();
1414 session->disable_record (false, true);
1418 case Session::Enabled:
1419 session->disable_record (false, true);
1422 //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
1426 ARDOUR_UI::transport_roll ()
1434 rolling = session->transport_rolling ();
1436 //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
1438 if (session->get_play_loop()) {
1439 session->request_play_loop (false);
1440 auto_loop_button.set_visual_state (1);
1441 roll_button.set_visual_state (1);
1442 } else if (session->get_play_range ()) {
1443 session->request_play_range (false);
1444 play_selection_button.set_visual_state (0);
1445 } else if (rolling) {
1446 session->request_locate (session->last_transport_start(), true);
1449 session->request_transport_speed (1.0f);
1453 ARDOUR_UI::transport_loop()
1456 if (session->get_play_loop()) {
1457 if (session->transport_rolling()) {
1458 Location * looploc = session->locations()->auto_loop_location();
1460 session->request_locate (looploc->start(), true);
1465 session->request_play_loop (true);
1471 ARDOUR_UI::transport_play_selection ()
1477 if (!session->get_play_range()) {
1478 session->request_stop ();
1481 editor->play_selection ();
1485 ARDOUR_UI::transport_rewind (int option)
1487 float current_transport_speed;
1490 current_transport_speed = session->transport_speed();
1492 if (current_transport_speed >= 0.0f) {
1495 session->request_transport_speed (-1.0f);
1498 session->request_transport_speed (-4.0f);
1501 session->request_transport_speed (-0.5f);
1506 session->request_transport_speed (current_transport_speed * 1.5f);
1512 ARDOUR_UI::transport_forward (int option)
1514 float current_transport_speed;
1517 current_transport_speed = session->transport_speed();
1519 if (current_transport_speed <= 0.0f) {
1522 session->request_transport_speed (1.0f);
1525 session->request_transport_speed (4.0f);
1528 session->request_transport_speed (0.5f);
1533 session->request_transport_speed (current_transport_speed * 1.5f);
1539 ARDOUR_UI::toggle_record_enable (uint32_t dstream)
1545 boost::shared_ptr<Route> r;
1547 if ((r = session->route_by_remote_id (dstream)) != 0) {
1551 if ((t = dynamic_cast<Track*>(r.get())) != 0) {
1552 t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled());
1561 ARDOUR_UI::queue_transport_change ()
1563 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1567 ARDOUR_UI::map_transport_state ()
1569 float sp = session->transport_speed();
1572 transport_rolling ();
1573 } else if (sp < 0.0f) {
1574 transport_rewinding ();
1575 } else if (sp > 0.0f) {
1576 transport_forwarding ();
1578 transport_stopped ();
1583 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1585 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1586 (int) adj.get_value()].c_str());
1590 ARDOUR_UI::engine_stopped ()
1592 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1593 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1594 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1598 ARDOUR_UI::engine_running ()
1600 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1601 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1602 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1604 Glib::RefPtr<Action> action;
1605 const char* action_name = 0;
1607 switch (engine->frames_per_cycle()) {
1609 action_name = X_("JACKLatency32");
1612 action_name = X_("JACKLatency64");
1615 action_name = X_("JACKLatency128");
1618 action_name = X_("JACKLatency512");
1621 action_name = X_("JACKLatency1024");
1624 action_name = X_("JACKLatency2048");
1627 action_name = X_("JACKLatency4096");
1630 action_name = X_("JACKLatency8192");
1633 /* XXX can we do anything useful ? */
1639 action = ActionManager::get_action (X_("JACK"), action_name);
1642 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
1643 ract->set_active ();
1649 ARDOUR_UI::engine_halted ()
1651 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1653 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1654 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1656 update_sample_rate (0);
1658 MessageDialog msg (*editor,
1660 JACK has either been shutdown or it\n\
1661 disconnected Ardour because Ardour\n\
1662 was not fast enough. You can save the\n\
1663 session and/or try to reconnect to JACK ."));
1669 ARDOUR_UI::do_engine_start ()
1677 error << _("Unable to start the session running")
1687 ARDOUR_UI::setup_theme ()
1689 theme_manager->setup_theme();
1693 ARDOUR_UI::update_clocks ()
1695 if (!editor || !editor->dragging_playhead()) {
1696 Clock (session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
1701 ARDOUR_UI::start_clocking ()
1703 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1707 ARDOUR_UI::stop_clocking ()
1709 clock_signal_connection.disconnect ();
1713 ARDOUR_UI::toggle_clocking ()
1716 if (clock_button.get_active()) {
1725 ARDOUR_UI::_blink (void *arg)
1728 ((ARDOUR_UI *) arg)->blink ();
1735 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1739 ARDOUR_UI::start_blinking ()
1741 /* Start the blink signal. Everybody with a blinking widget
1742 uses Blink to drive the widget's state.
1745 if (blink_timeout_tag < 0) {
1747 blink_timeout_tag = g_timeout_add (240, _blink, this);
1752 ARDOUR_UI::stop_blinking ()
1754 if (blink_timeout_tag >= 0) {
1755 g_source_remove (blink_timeout_tag);
1756 blink_timeout_tag = -1;
1761 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1767 if (io.n_inputs() == 0) {
1772 /* XXX we're not handling multiple ports yet. */
1774 const char **connections = io.input(0)->get_connections();
1776 if (connections == 0 || connections[0] == '\0') {
1779 buf = connections[0];
1786 if (io.n_outputs() == 0) {
1791 /* XXX we're not handling multiple ports yet. */
1793 const char **connections = io.output(0)->get_connections();
1795 if (connections == 0 || connections[0] == '\0') {
1798 buf = connections[0];
1805 /** Ask the user for the name of a new shapshot and then take it.
1808 ARDOUR_UI::snapshot_session ()
1810 ArdourPrompter prompter (true);
1814 struct tm local_time;
1817 localtime_r (&n, &local_time);
1818 strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time);
1820 prompter.set_name ("Prompter");
1821 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1822 prompter.set_prompt (_("Name of New Snapshot"));
1823 prompter.set_initial_text (timebuf);
1825 switch (prompter.run()) {
1826 case RESPONSE_ACCEPT:
1827 prompter.get_result (snapname);
1828 if (snapname.length()){
1829 save_state (snapname);
1839 ARDOUR_UI::save_state (const string & name)
1841 (void) save_state_canfail (name);
1845 ARDOUR_UI::save_state_canfail (string name)
1850 if (name.length() == 0) {
1851 name = session->snap_name();
1854 if ((ret = session->save_state (name)) != 0) {
1858 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1863 ARDOUR_UI::primary_clock_value_changed ()
1866 session->request_locate (primary_clock.current_time ());
1871 ARDOUR_UI::big_clock_value_changed ()
1874 session->request_locate (big_clock.current_time ());
1879 ARDOUR_UI::secondary_clock_value_changed ()
1882 session->request_locate (secondary_clock.current_time ());
1887 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1893 switch (session->record_status()) {
1894 case Session::Enabled:
1896 rec_button.set_visual_state (2);
1898 rec_button.set_visual_state (0);
1902 case Session::Recording:
1903 rec_button.set_visual_state (1);
1907 rec_button.set_visual_state (0);
1913 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1921 ARDOUR_UI::save_template ()
1924 ArdourPrompter prompter (true);
1927 if (!check_audioengine()) {
1931 prompter.set_name (X_("Prompter"));
1932 prompter.set_prompt (_("Name for mix template:"));
1933 prompter.set_initial_text(session->name() + _("-template"));
1934 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1936 switch (prompter.run()) {
1937 case RESPONSE_ACCEPT:
1938 prompter.get_result (name);
1940 if (name.length()) {
1941 session->save_template (name);
1951 ARDOUR_UI::fontconfig_dialog ()
1954 /* X11 users will always have fontconfig info around, but new GTK-OSX users
1955 may not and it can take a while to build it. Warn them.
1958 Glib::ustring fontconfig = Glib::build_filename (Glib::get_home_dir(), ".fontconfig");
1960 if (!Glib::file_test (fontconfig, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
1961 MessageDialog msg (*new_session_dialog,
1962 _("Welcome to Ardour.\n\n"
1963 "The program will take a bit longer to start up\n"
1964 "while the system fonts are checked.\n\n"
1965 "This will only be done once, and you will\n"
1966 "not see this message again\n"),
1979 ARDOUR_UI::parse_cmdline_path (const Glib::ustring& cmdline_path, Glib::ustring& session_name, Glib::ustring& session_path, bool& existing_session)
1981 existing_session = false;
1983 if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_DIR)) {
1984 session_path = cmdline_path;
1985 existing_session = true;
1986 } else if (Glib::file_test (cmdline_path, Glib::FILE_TEST_IS_REGULAR)) {
1987 session_path = Glib::path_get_dirname (string (cmdline_path));
1988 existing_session = true;
1990 /* it doesn't exist, assume the best */
1991 session_path = Glib::path_get_dirname (string (cmdline_path));
1994 session_name = basename_nosuffix (string (cmdline_path));
1998 ARDOUR_UI::load_cmdline_session (const Glib::ustring& session_name, const Glib::ustring& session_path, bool& existing_session)
2000 /* when this is called, the backend audio system must be running */
2002 /* the main idea here is to deal with the fact that a cmdline argument for the session
2003 can be interpreted in different ways - it could be a directory or a file, and before
2004 we load, we need to know both the session directory and the snapshot (statefile) within it
2005 that we are supposed to use.
2008 if (session_name.length() == 0 || session_path.length() == 0) {
2012 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_DIR)) {
2014 Glib::ustring predicted_session_file;
2016 predicted_session_file = session_path;
2017 predicted_session_file += '/';
2018 predicted_session_file += session_name;
2019 predicted_session_file += Session::statefile_suffix();
2021 if (Glib::file_test (predicted_session_file, Glib::FILE_TEST_EXISTS)) {
2022 existing_session = true;
2025 } else if (Glib::file_test (session_path, Glib::FILE_TEST_EXISTS)) {
2027 if (session_path.find (Session::statefile_suffix()) == session_path.length() - 7) {
2028 /* existing .ardour file */
2029 existing_session = true;
2033 existing_session = false;
2036 /* lets just try to load it */
2038 if (create_engine ()) {
2039 backend_audio_error (false, new_session_dialog);
2043 return load_session (session_path, session_name);
2047 ARDOUR_UI::ask_about_loading_existing_session (const Glib::ustring& session_path)
2049 Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2051 MessageDialog msg (str,
2053 Gtk::MESSAGE_WARNING,
2054 Gtk::BUTTONS_YES_NO,
2058 msg.set_name (X_("CleanupDialog"));
2059 msg.set_wmclass (X_("existing_session"), "Ardour");
2060 msg.set_position (Gtk::WIN_POS_MOUSE);
2063 switch (msg.run()) {
2072 ARDOUR_UI::build_session_from_nsd (const Glib::ustring& session_path, const Glib::ustring& session_name)
2077 AutoConnectOption iconnect;
2078 AutoConnectOption oconnect;
2082 if (Profile->get_sae()) {
2086 iconnect = AutoConnectPhysical;
2087 oconnect = AutoConnectMaster;
2088 nphysin = 0; // use all available
2089 nphysout = 0; // use all available
2093 /* get settings from advanced section of NSD */
2095 if (new_session_dialog->create_control_bus()) {
2096 cchns = (uint32_t) new_session_dialog->control_channel_count();
2101 if (new_session_dialog->create_master_bus()) {
2102 mchns = (uint32_t) new_session_dialog->master_channel_count();
2107 if (new_session_dialog->connect_inputs()) {
2108 iconnect = AutoConnectPhysical;
2110 iconnect = AutoConnectOption (0);
2113 /// @todo some minor tweaks.
2115 if (new_session_dialog->connect_outs_to_master()) {
2116 oconnect = AutoConnectMaster;
2117 } else if (new_session_dialog->connect_outs_to_physical()) {
2118 oconnect = AutoConnectPhysical;
2120 oconnect = AutoConnectOption (0);
2123 nphysin = (uint32_t) new_session_dialog->input_limit_count();
2124 nphysout = (uint32_t) new_session_dialog->output_limit_count();
2127 if (build_session (session_path,
2135 engine->frame_rate() * 60 * 5)) {
2144 ARDOUR_UI::end_loading_messages ()
2150 ARDOUR_UI::loading_message (const std::string& msg)
2153 splash->message (msg);
2158 ARDOUR_UI::idle_load (const Glib::ustring& path)
2161 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2162 /* /path/to/foo => /path/to/foo, foo */
2163 load_session (path, basename_nosuffix (path));
2165 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2166 load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2169 ARDOUR_COMMAND_LINE::session_name = path;
2170 if (new_session_dialog) {
2171 /* make it break out of Dialog::run() and
2174 new_session_dialog->response (1);
2180 ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
2182 bool existing_session = false;
2183 Glib::ustring session_name;
2184 Glib::ustring session_path;
2185 Glib::ustring template_name;
2189 response = Gtk::RESPONSE_NONE;
2191 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2193 parse_cmdline_path (ARDOUR_COMMAND_LINE::session_name, session_name, session_path, existing_session);
2195 /* don't ever reuse this */
2197 ARDOUR_COMMAND_LINE::session_name = string();
2199 if (existing_session && backend_audio_is_running) {
2201 /* just load the thing already */
2203 if (load_cmdline_session (session_name, session_path, existing_session) == 0) {
2208 /* make the NSD use whatever information we have */
2210 new_session_dialog->set_session_name (session_name);
2211 new_session_dialog->set_session_folder (session_path);
2214 /* loading failed, or we need the NSD for something */
2216 new_session_dialog->set_modal (false);
2217 new_session_dialog->set_position (WIN_POS_CENTER);
2218 new_session_dialog->set_current_page (0);
2219 new_session_dialog->set_existing_session (existing_session);
2220 new_session_dialog->reset_recent();
2223 new_session_dialog->set_have_engine (backend_audio_is_running);
2224 new_session_dialog->present ();
2225 response = new_session_dialog->run ();
2227 _session_is_new = false;
2229 /* handle possible negative responses */
2233 /* sent by idle_load, meaning restart the whole process again */
2234 new_session_dialog->hide();
2235 new_session_dialog->reset();
2239 case Gtk::RESPONSE_CANCEL:
2240 case Gtk::RESPONSE_DELETE_EVENT:
2244 new_session_dialog->hide ();
2247 case Gtk::RESPONSE_NONE:
2248 /* "Clear" was pressed */
2252 fontconfig_dialog();
2254 if (!backend_audio_is_running) {
2255 int ret = new_session_dialog->engine_control.setup_engine ();
2258 } else if (ret > 0) {
2259 response = Gtk::RESPONSE_REJECT;
2264 if (create_engine ()) {
2266 backend_audio_error (!backend_audio_is_running, new_session_dialog);
2269 new_session_dialog->set_existing_session (false);
2270 new_session_dialog->set_current_page (2);
2272 response = Gtk::RESPONSE_NONE;
2276 backend_audio_is_running = true;
2278 if (response == Gtk::RESPONSE_OK) {
2280 session_name = new_session_dialog->session_name();
2282 if (session_name.empty()) {
2283 response = Gtk::RESPONSE_NONE;
2287 /* if the user mistakenly typed path information into the session filename entry,
2288 convert what they typed into a path & a name
2291 if (session_name[0] == '/' ||
2292 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
2293 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
2295 session_path = Glib::path_get_dirname (session_name);
2296 session_name = Glib::path_get_basename (session_name);
2300 session_path = new_session_dialog->session_folder();
2303 template_name = Glib::ustring();
2304 switch (new_session_dialog->which_page()) {
2306 case NewSessionDialog::OpenPage:
2307 case NewSessionDialog::EnginePage:
2311 case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
2313 should_be_new = true;
2315 //XXX This is needed because session constructor wants a
2316 //non-existant path. hopefully this will be fixed at some point.
2318 session_path = Glib::build_filename (session_path, session_name);
2320 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
2322 if (ask_about_loading_existing_session (session_path)) {
2325 response = RESPONSE_NONE;
2330 _session_is_new = true;
2332 if (new_session_dialog->use_session_template()) {
2334 template_name = new_session_dialog->session_template_name();
2338 if (build_session_from_nsd (session_path, session_name)) {
2339 response = RESPONSE_NONE;
2351 new_session_dialog->hide ();
2353 if (load_session (session_path, session_name, template_name)) {
2355 response = Gtk::RESPONSE_NONE;
2359 if (response == Gtk::RESPONSE_NONE) {
2360 new_session_dialog->set_existing_session (false);
2361 new_session_dialog->reset ();
2365 } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
2369 new_session_dialog->hide();
2370 new_session_dialog->reset();
2371 goto_editor_window ();
2376 ARDOUR_UI::close_session ()
2378 if (!check_audioengine()) {
2382 unload_session (true);
2384 get_session_parameters (true, false);
2388 ARDOUR_UI::load_session (const Glib::ustring& path, const Glib::ustring& snap_name, Glib::ustring mix_template)
2390 Session *new_session;
2394 session_loaded = false;
2396 if (!check_audioengine()) {
2400 unload_status = unload_session ();
2402 if (unload_status < 0) {
2404 } else if (unload_status > 0) {
2409 /* if it already exists, we must have write access */
2411 if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
2412 MessageDialog msg (*editor, _("You do not have write access to this session.\n"
2413 "This prevents the session from being loaded."));
2419 loading_message (_("Please wait while Ardour loads your session"));
2422 new_session = new Session (*engine, path, snap_name, mix_template);
2425 /* this one is special */
2427 catch (AudioEngine::PortRegistrationFailure& err) {
2429 MessageDialog msg (err.what(),
2432 Gtk::BUTTONS_OK_CANCEL);
2434 msg.set_title (_("Loading Error"));
2435 msg.set_secondary_text (_("Click the OK button to try again."));
2436 msg.set_position (Gtk::WIN_POS_CENTER);
2440 int response = msg.run ();
2445 case RESPONSE_CANCEL:
2455 MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
2458 Gtk::BUTTONS_OK_CANCEL);
2460 msg.set_title (_("Loading Error"));
2461 msg.set_secondary_text (_("Click the OK button to try again."));
2462 msg.set_position (Gtk::WIN_POS_CENTER);
2466 int response = msg.run ();
2471 case RESPONSE_CANCEL:
2479 connect_to_session (new_session);
2481 Config->set_current_owner (ConfigVariableBase::Interface);
2483 session_loaded = true;
2485 goto_editor_window ();
2488 session->set_clean ();
2499 ARDOUR_UI::build_session (const Glib::ustring& path, const Glib::ustring& snap_name,
2500 uint32_t control_channels,
2501 uint32_t master_channels,
2502 AutoConnectOption input_connect,
2503 AutoConnectOption output_connect,
2506 nframes_t initial_length)
2508 Session *new_session;
2511 if (!check_audioengine()) {
2515 session_loaded = false;
2517 x = unload_session ();
2525 _session_is_new = true;
2528 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2529 control_channels, master_channels, nphysin, nphysout, initial_length);
2534 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
2540 connect_to_session (new_session);
2542 session_loaded = true;
2550 editor->show_window ();
2561 ARDOUR_UI::show_about ()
2565 about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
2572 ARDOUR_UI::hide_about ()
2575 about->get_window()->set_cursor ();
2581 ARDOUR_UI::about_signal_response(int response)
2587 ARDOUR_UI::show_splash ()
2591 splash = new Splash;
2599 splash->queue_draw ();
2600 splash->get_window()->process_updates (true);
2605 ARDOUR_UI::hide_splash ()
2613 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
2617 removed = rep.paths.size();
2620 MessageDialog msgd (*editor,
2621 _("No audio files were ready for cleanup"),
2624 (Gtk::ButtonsType)(Gtk::BUTTONS_OK) );
2625 msgd.set_secondary_text (_("If this seems suprising, \n\
2626 check for any existing snapshots.\n\
2627 These may still include regions that\n\
2628 require some unused files to continue to exist."));
2634 ArdourDialog results (_("ardour: cleanup"), true, false);
2636 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2637 CleanupResultsModelColumns() {
2641 Gtk::TreeModelColumn<Glib::ustring> visible_name;
2642 Gtk::TreeModelColumn<Glib::ustring> fullpath;
2646 CleanupResultsModelColumns results_columns;
2647 Glib::RefPtr<Gtk::ListStore> results_model;
2648 Gtk::TreeView results_display;
2650 results_model = ListStore::create (results_columns);
2651 results_display.set_model (results_model);
2652 results_display.append_column (list_title, results_columns.visible_name);
2654 results_display.set_name ("CleanupResultsList");
2655 results_display.set_headers_visible (true);
2656 results_display.set_headers_clickable (false);
2657 results_display.set_reorderable (false);
2659 Gtk::ScrolledWindow list_scroller;
2662 Gtk::HBox dhbox; // the hbox for the image and text
2663 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
2664 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
2666 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
2668 if (rep.space < 1048576.0f) {
2670 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2672 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
2676 txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2678 txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
2682 dhbox.pack_start (*dimage, true, false, 5);
2683 dhbox.pack_start (txt, true, false, 5);
2685 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2686 TreeModel::Row row = *(results_model->append());
2687 row[results_columns.visible_name] = *i;
2688 row[results_columns.fullpath] = *i;
2691 list_scroller.add (results_display);
2692 list_scroller.set_size_request (-1, 150);
2693 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2695 dvbox.pack_start (dhbox, true, false, 5);
2696 dvbox.pack_start (list_scroller, true, false, 5);
2697 ddhbox.pack_start (dvbox, true, false, 5);
2699 results.get_vbox()->pack_start (ddhbox, true, false, 5);
2700 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
2701 results.set_default_response (RESPONSE_CLOSE);
2702 results.set_position (Gtk::WIN_POS_MOUSE);
2703 results.show_all_children ();
2704 results.set_resizable (false);
2711 ARDOUR_UI::cleanup ()
2714 /* shouldn't happen: menu item is insensitive */
2719 MessageDialog checker (_("Are you sure you want to cleanup?"),
2721 Gtk::MESSAGE_QUESTION,
2722 (Gtk::ButtonsType)(Gtk::BUTTONS_NONE));
2724 checker.set_secondary_text(_("Cleanup is a destructive operation.\n\
2725 ALL undo/redo information will be lost if you cleanup.\n\
2726 After cleanup, unused audio files will be moved to a \
2727 \"dead sounds\" location."));
2729 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2730 checker.add_button (_("Clean Up"), RESPONSE_ACCEPT);
2731 checker.set_default_response (RESPONSE_CANCEL);
2733 checker.set_name (_("CleanupDialog"));
2734 checker.set_wmclass (X_("ardour_cleanup"), "Ardour");
2735 checker.set_position (Gtk::WIN_POS_MOUSE);
2737 switch (checker.run()) {
2738 case RESPONSE_ACCEPT:
2744 Session::cleanup_report rep;
2746 editor->prepare_for_cleanup ();
2748 /* do not allow flush until a session is reloaded */
2750 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
2752 act->set_sensitive (false);
2755 if (session->cleanup_sources (rep)) {
2756 editor->finish_cleanup ();
2760 editor->finish_cleanup ();
2763 display_cleanup_results (rep,
2766 The following %1 %2 not in use and \n\
2767 have been moved to:\n\
2769 Flushing the wastebasket will \n\
2770 release an additional\n\
2771 %4 %5bytes of disk space.\n"
2777 ARDOUR_UI::flush_trash ()
2780 /* shouldn't happen: menu item is insensitive */
2784 Session::cleanup_report rep;
2786 if (session->cleanup_trash_sources (rep)) {
2790 display_cleanup_results (rep,
2792 _("The following %1 %2 deleted from\n\
2794 releasing %4 %5bytes of disk space"));
2798 ARDOUR_UI::add_route (Gtk::Window* float_window)
2806 if (add_route_dialog == 0) {
2807 add_route_dialog = new AddRouteDialog;
2809 add_route_dialog->set_transient_for (*float_window);
2813 if (add_route_dialog->is_visible()) {
2814 /* we're already doing this */
2818 ResponseType r = (ResponseType) add_route_dialog->run ();
2820 add_route_dialog->hide();
2823 case RESPONSE_ACCEPT:
2830 if ((count = add_route_dialog->count()) <= 0) {
2834 uint32_t input_chan = add_route_dialog->channels ();
2835 uint32_t output_chan;
2836 string name_template = add_route_dialog->name_template ();
2837 bool track = add_route_dialog->track ();
2839 AutoConnectOption oac = Config->get_output_auto_connect();
2841 if (oac & AutoConnectMaster) {
2842 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2844 output_chan = input_chan;
2847 /* XXX do something with name template */
2849 cerr << "Adding with " << input_chan << " in and " << output_chan << "out\n";
2852 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count);
2854 session_add_audio_bus (input_chan, output_chan, count);
2859 ARDOUR_UI::mixer_settings () const
2864 node = session->instant_xml(X_("Mixer"), session->path());
2866 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2870 node = new XMLNode (X_("Mixer"));
2877 ARDOUR_UI::editor_settings () const
2882 node = session->instant_xml(X_("Editor"), session->path());
2884 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2888 node = new XMLNode (X_("Editor"));
2894 ARDOUR_UI::keyboard_settings () const
2898 node = Config->extra_xml(X_("Keyboard"));
2901 node = new XMLNode (X_("Keyboard"));
2907 ARDOUR_UI::create_xrun_marker(nframes_t where)
2909 ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::create_xrun_marker), where));
2910 editor->mouse_add_new_marker (where, false, true);
2914 ARDOUR_UI::halt_on_xrun_message ()
2916 MessageDialog msg (*editor,
2917 _("Recording was stopped because your system could not keep up."));
2922 ARDOUR_UI::xrun_handler(nframes_t where)
2924 if (Config->get_create_xrun_marker() && session->actively_recording()) {
2925 create_xrun_marker(where);
2928 if (Config->get_stop_recording_on_xrun() && session->actively_recording()) {
2929 halt_on_xrun_message ();
2934 ARDOUR_UI::disk_overrun_handler ()
2936 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
2938 if (!have_disk_speed_dialog_displayed) {
2939 have_disk_speed_dialog_displayed = true;
2940 MessageDialog* msg = new MessageDialog (*editor, _("\
2941 The disk system on your computer\n\
2942 was not able to keep up with Ardour.\n\
2944 Specifically, it failed to write data to disk\n\
2945 quickly enough to keep up with recording.\n"));
2946 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2952 ARDOUR_UI::disk_underrun_handler ()
2954 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2956 if (!have_disk_speed_dialog_displayed) {
2957 have_disk_speed_dialog_displayed = true;
2958 MessageDialog* msg = new MessageDialog (*editor,
2959 _("The disk system on your computer\n\
2960 was not able to keep up with Ardour.\n\
2962 Specifically, it failed to read data from disk\n\
2963 quickly enough to keep up with playback.\n"));
2964 msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
2970 ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg)
2972 have_disk_speed_dialog_displayed = false;
2977 ARDOUR_UI::session_dialog (std::string msg)
2979 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
2984 d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
2986 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
2995 ARDOUR_UI::pending_state_dialog ()
2997 HBox* hbox = new HBox();
2998 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
2999 ArdourDialog dialog (_("Crash Recovery"), true);
3001 This session appears to have been in\n\
3002 middle of recording when ardour or\n\
3003 the computer was shutdown.\n\
3005 Ardour can recover any captured audio for\n\
3006 you, or it can ignore it. Please decide\n\
3007 what you would like to do.\n"));
3008 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3009 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3010 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3011 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3012 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
3013 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
3014 dialog.set_default_response (RESPONSE_ACCEPT);
3015 dialog.set_position (WIN_POS_CENTER);
3020 switch (dialog.run ()) {
3021 case RESPONSE_ACCEPT:
3029 ARDOUR_UI::sr_mismatch_dialog (nframes_t desired, nframes_t actual)
3031 HBox* hbox = new HBox();
3032 Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
3033 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
3034 Label message (string_compose (_("\
3035 This session was created with a sample rate of %1 Hz\n\
3037 The audioengine is currently running at %2 Hz\n"), desired, actual));
3039 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
3040 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
3041 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
3042 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
3043 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
3044 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
3045 dialog.set_default_response (RESPONSE_ACCEPT);
3046 dialog.set_position (WIN_POS_CENTER);
3051 switch (dialog.run ()) {
3052 case RESPONSE_ACCEPT:
3061 ARDOUR_UI::disconnect_from_jack ()
3064 if( engine->disconnect_from_jack ()) {
3065 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
3069 update_sample_rate (0);
3074 ARDOUR_UI::reconnect_to_jack ()
3077 if (engine->reconnect_to_jack ()) {
3078 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
3082 update_sample_rate (0);
3087 ARDOUR_UI::use_config ()
3089 Glib::RefPtr<Action> act;
3091 switch (Config->get_native_file_data_format ()) {
3093 act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat"));
3096 act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit"));
3099 act = ActionManager::get_action (X_("options"), X_("FileDataFormat16bit"));
3104 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3105 ract->set_active ();
3108 switch (Config->get_native_file_header_format ()) {
3110 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF"));
3113 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE"));
3116 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64"));
3119 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML"));
3122 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64"));
3125 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF"));
3128 act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF"));
3133 Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic(act);
3134 ract->set_active ();
3137 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
3139 set_transport_controllable_state (*node);
3144 ARDOUR_UI::update_transport_clocks (nframes_t pos)
3146 if (Config->get_primary_clock_delta_edit_cursor()) {
3147 primary_clock.set (pos, false, editor->get_preferred_edit_position(), 1);
3149 primary_clock.set (pos, 0, true);
3152 if (Config->get_secondary_clock_delta_edit_cursor()) {
3153 secondary_clock.set (pos, false, editor->get_preferred_edit_position(), 2);
3155 secondary_clock.set (pos);
3158 if (big_clock_window) {
3159 big_clock.set (pos);
3164 ARDOUR_UI::record_state_changed ()
3166 ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed));
3168 if (!session || !big_clock_window) {
3169 /* why bother - the clock isn't visible */
3173 switch (session->record_status()) {
3174 case Session::Recording:
3175 big_clock.set_widget_name ("BigClockRecording");
3178 big_clock.set_widget_name ("BigClockNonRecording");
3184 ARDOUR_UI::first_idle ()
3187 session->allow_auto_play (true);
3191 editor->first_idle();
3194 Keyboard::set_can_save_keybindings (true);
3199 ARDOUR_UI::store_clock_modes ()
3201 XMLNode* node = new XMLNode(X_("ClockModes"));
3203 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
3204 node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode()));
3207 session->add_extra_xml (*node);
3208 session->set_dirty ();
3213 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
3214 : Controllable (name), ui (u), type(tp)
3220 ARDOUR_UI::TransportControllable::set_value (float val)
3222 if (type == ShuttleControl) {
3229 fract = -((0.5f - val)/0.5f);
3231 fract = ((val - 0.5f)/0.5f);
3235 ui.set_shuttle_fract (fract);
3240 /* do nothing: these are radio-style actions */
3244 const char *action = 0;
3248 action = X_("Roll");
3251 action = X_("Stop");
3254 action = X_("Goto Start");
3257 action = X_("Goto End");
3260 action = X_("Loop");
3263 action = X_("Play Selection");
3266 action = X_("Record");
3276 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
3284 ARDOUR_UI::TransportControllable::get_value (void) const
3303 case ShuttleControl:
3313 ARDOUR_UI::TransportControllable::set_id (const string& str)
3319 ARDOUR_UI::setup_profile ()
3321 if (gdk_screen_width() < 1200) {
3322 Profile->set_small_screen ();
3325 if (getenv ("ARDOUR_SAE")) {
3326 Profile->set_sae ();
3327 Profile->set_single_package ();