2 Copyright (C) 1999-2013 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.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "main_clock.h"
128 #include "missing_file_dialog.h"
129 #include "missing_plugin_dialog.h"
130 #include "mixer_ui.h"
131 #include "meterbridge.h"
132 #include "mouse_cursors.h"
135 #include "pingback.h"
136 #include "processor_box.h"
137 #include "prompter.h"
138 #include "public_editor.h"
139 #include "rc_option_editor.h"
140 #include "route_time_axis.h"
141 #include "route_params_ui.h"
142 #include "save_as_dialog.h"
143 #include "session_dialog.h"
144 #include "session_metadata_dialog.h"
145 #include "session_option_editor.h"
146 #include "shuttle_control.h"
147 #include "speaker_dialog.h"
150 #include "theme_manager.h"
151 #include "time_axis_view_item.h"
154 #include "video_server_dialog.h"
155 #include "add_video_dialog.h"
156 #include "transcode_video_dialog.h"
160 using namespace ARDOUR;
161 using namespace ARDOUR_UI_UTILS;
163 using namespace Gtkmm2ext;
166 using namespace Editing;
168 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
170 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
171 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
174 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
176 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
177 "Would you like these files to be copied and used for %1 %2.x?\n\n"
178 "(This will require you to restart %1.)"),
179 PROGRAM_NAME, PROGRAM_VERSION, version),
180 false, /* no markup */
183 true /* modal, though it hardly matters since it is the only window */
186 msg.set_default_response (Gtk::RESPONSE_YES);
189 return (msg.run() == Gtk::RESPONSE_YES);
193 libxml_generic_error_func (void* /* parsing_context*/,
201 vsnprintf (buf, sizeof (buf), msg, ap);
202 error << buf << endmsg;
207 libxml_structured_error_func (void* /* parsing_context*/,
215 replace_all (msg, "\n", "");
217 if (err->file && err->line) {
218 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
221 error << ':' << err->int2;
228 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
231 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
233 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
234 >>>>>>> first compilable version of tabbable design.
235 , session_loaded (false)
236 , gui_object_state (new GUIObjectState)
237 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
238 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
239 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
241 , global_actions (X_("global"))
242 , ignore_dual_punch (false)
247 , _mixer_on_top (false)
248 , _initial_verbose_plugin_scan (false)
249 , first_time_engine_run (true)
250 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
251 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
252 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
253 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
254 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
255 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
256 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
257 , auto_return_button (ArdourButton::led_default_elements)
258 , follow_edits_button (ArdourButton::led_default_elements)
259 , auto_input_button (ArdourButton::led_default_elements)
260 , auditioning_alert_button (_("Audition"))
261 , solo_alert_button (_("Solo"))
262 , feedback_alert_button (_("Feedback"))
263 , error_alert_button ( ArdourButton::just_led_default_elements )
265 , editor_meter_peak_display()
266 , _numpad_locate_happening (false)
267 , _session_is_new (false)
268 , last_key_press_time (0)
271 , rc_option_editor (0)
272 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
273 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
274 , about (X_("about"), _("About"))
275 , location_ui (X_("locations"), _("Locations"))
276 , route_params (X_("inspector"), _("Tracks and Busses"))
277 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
278 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
279 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
280 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
281 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
282 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
283 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
284 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
285 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
286 , video_server_process (0)
288 , have_configure_timeout (false)
289 , last_configure_time (0)
291 , have_disk_speed_dialog_displayed (false)
292 , _status_bar_visibility (X_("status-bar"))
293 , _feedback_exists (false)
294 , _log_not_acknowledged (LogLevelNone)
295 , duplicate_routes_dialog (0)
297 Gtkmm2ext::init (localedir);
299 UIConfiguration::instance().post_gui_init ();
301 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
302 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
304 /* configuration was modified, exit immediately */
308 if (theArdourUI == 0) {
312 /* stop libxml from spewing to stdout/stderr */
314 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
315 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
317 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
318 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
319 UIConfiguration::instance().map_parameters (pc);
321 roll_button.set_controllable (roll_controllable);
322 stop_button.set_controllable (stop_controllable);
323 goto_start_button.set_controllable (goto_start_controllable);
324 goto_end_button.set_controllable (goto_end_controllable);
325 auto_loop_button.set_controllable (auto_loop_controllable);
326 play_selection_button.set_controllable (play_selection_controllable);
327 rec_button.set_controllable (rec_controllable);
329 roll_button.set_name ("transport button");
330 stop_button.set_name ("transport button");
331 goto_start_button.set_name ("transport button");
332 goto_end_button.set_name ("transport button");
333 auto_loop_button.set_name ("transport button");
334 play_selection_button.set_name ("transport button");
335 rec_button.set_name ("transport recenable button");
336 midi_panic_button.set_name ("transport button");
338 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
339 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
341 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
343 /* handle dialog requests */
345 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
347 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
349 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
351 /* handle Audio/MIDI setup when session requires it */
353 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
355 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
357 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
359 /* handle requests to quit (coming from JACK session) */
361 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
363 /* tell the user about feedback */
365 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
366 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
368 /* handle requests to deal with missing files */
370 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
372 /* and ambiguous files */
374 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
376 /* also plugin scan messages */
377 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
378 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
380 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
382 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
385 /* lets get this party started */
387 setup_gtk_ardour_enums ();
390 SessionEvent::create_per_thread_pool ("GUI", 4096);
392 /* we like keyboards */
394 keyboard = new ArdourKeyboard(*this);
396 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
398 keyboard->set_state (*node, Stateful::loading_state_version);
401 UIConfiguration::instance().reset_dpi ();
403 TimeAxisViewItem::set_constant_heights ();
405 /* Set this up so that our window proxies can register actions */
407 ActionManager::init ();
409 /* The following must happen after ARDOUR::init() so that Config is set up */
411 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
414 key_editor.set_state (*ui_xml, 0);
415 session_option_editor.set_state (*ui_xml, 0);
416 speaker_config_window.set_state (*ui_xml, 0);
417 about.set_state (*ui_xml, 0);
418 add_route_dialog.set_state (*ui_xml, 0);
419 add_video_dialog.set_state (*ui_xml, 0);
420 route_params.set_state (*ui_xml, 0);
421 bundle_manager.set_state (*ui_xml, 0);
422 location_ui.set_state (*ui_xml, 0);
423 big_clock_window.set_state (*ui_xml, 0);
424 audio_port_matrix.set_state (*ui_xml, 0);
425 midi_port_matrix.set_state (*ui_xml, 0);
426 export_video_dialog.set_state (*ui_xml, 0);
429 /* Separate windows */
431 WM::Manager::instance().register_window (&key_editor);
432 WM::Manager::instance().register_window (&session_option_editor);
433 WM::Manager::instance().register_window (&speaker_config_window);
434 WM::Manager::instance().register_window (&about);
435 WM::Manager::instance().register_window (&add_route_dialog);
436 WM::Manager::instance().register_window (&add_video_dialog);
437 WM::Manager::instance().register_window (&route_params);
438 WM::Manager::instance().register_window (&audio_midi_setup);
439 WM::Manager::instance().register_window (&export_video_dialog);
440 WM::Manager::instance().register_window (&bundle_manager);
441 WM::Manager::instance().register_window (&location_ui);
442 WM::Manager::instance().register_window (&big_clock_window);
443 WM::Manager::instance().register_window (&audio_port_matrix);
444 WM::Manager::instance().register_window (&midi_port_matrix);
446 /* Trigger setting up the color scheme and loading the GTK RC file */
448 UIConfiguration::instance().load_rc_file (false);
450 _process_thread = new ProcessThread ();
451 _process_thread->init ();
453 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
458 GlobalPortMatrixWindow*
459 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
464 return new GlobalPortMatrixWindow (_session, type);
468 ARDOUR_UI::attach_to_engine ()
470 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
471 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
475 ARDOUR_UI::engine_stopped ()
477 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
478 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
479 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
480 update_sample_rate (0);
485 ARDOUR_UI::engine_running ()
487 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
488 if (first_time_engine_run) {
490 first_time_engine_run = false;
494 _session->reset_xrun_count ();
496 update_disk_space ();
498 update_xrun_count ();
499 update_sample_rate (AudioEngine::instance()->sample_rate());
500 update_timecode_format ();
501 update_peak_thread_work ();
502 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
503 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
507 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
509 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
510 /* we can't rely on the original string continuing to exist when we are called
511 again in the GUI thread, so make a copy and note that we need to
514 char *copy = strdup (reason);
515 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
519 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
520 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
522 update_sample_rate (0);
526 /* if the reason is a non-empty string, it means that the backend was shutdown
527 rather than just Ardour.
530 if (strlen (reason)) {
531 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
533 msgstr = string_compose (_("\
534 The audio backend has either been shutdown or it\n\
535 disconnected %1 because %1\n\
536 was not fast enough. Try to restart\n\
537 the audio backend and save the session."), PROGRAM_NAME);
540 MessageDialog msg (_main_window, msgstr);
541 pop_back_splash (msg);
545 free (const_cast<char*> (reason));
550 ARDOUR_UI::post_engine ()
552 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
554 #ifdef AUDIOUNIT_SUPPORT
556 if (AUPluginInfo::au_get_crashlog(au_msg)) {
557 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
558 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
559 info << au_msg << endmsg;
563 ARDOUR::init_post_engine ();
565 /* connect to important signals */
567 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
568 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
569 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
570 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
571 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
573 if (setup_windows ()) {
574 throw failed_constructor ();
577 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
578 XMLNode* n = Config->extra_xml (X_("UI"));
580 _status_bar_visibility.set_state (*n);
583 check_memory_locking();
585 /* this is the first point at which all the possible actions are
586 * available, because some of the available actions are dependent on
587 * aspects of the engine/backend.
590 if (ARDOUR_COMMAND_LINE::show_key_actions) {
593 vector<string> paths;
594 vector<string> labels;
595 vector<string> tooltips;
597 vector<Glib::RefPtr<Gtk::Action> > actions;
599 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
601 vector<string>::iterator k;
602 vector<string>::iterator p;
604 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
609 cout << *p << " => " << *k << endl;
613 halt_connection.disconnect ();
614 AudioEngine::instance()->stop ();
618 /* this being a GUI and all, we want peakfiles */
620 AudioFileSource::set_build_peakfiles (true);
621 AudioFileSource::set_build_missing_peakfiles (true);
623 /* set default clock modes */
625 primary_clock->set_mode (AudioClock::Timecode);
626 secondary_clock->set_mode (AudioClock::BBT);
628 /* start the time-of-day-clock */
631 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
632 update_wall_clock ();
633 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
638 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
639 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
640 Config->map_parameters (pc);
642 UIConfiguration::instance().map_parameters (pc);
646 ARDOUR_UI::~ARDOUR_UI ()
648 UIConfiguration::instance().save_state();
652 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
653 // don't bother at 'real' exit. the OS cleans up for us.
655 delete primary_clock;
656 delete secondary_clock;
657 delete _process_thread;
662 delete gui_object_state;
663 FastMeter::flush_pattern_cache ();
664 PixFader::flush_pattern_cache ();
668 /* Small trick to flush main-thread event pool.
669 * Other thread-pools are destroyed at pthread_exit(),
670 * but tmain thread termination is too late to trigger Pool::~Pool()
672 SessionEvent* ev = new SessionEvent (SessionEvent::SetTransportSpeed, SessionEvent::Clear, SessionEvent::Immediate, 0, 0); // get the pool reference, values don't matter since the event is never queued.
673 delete ev->event_pool();
678 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
680 if (Splash::instance()) {
681 Splash::instance()->pop_back_for (win);
686 ARDOUR_UI::configure_timeout ()
688 if (last_configure_time == 0) {
689 /* no configure events yet */
693 /* force a gap of 0.5 seconds since the last configure event
696 if (get_microseconds() - last_configure_time < 500000) {
699 have_configure_timeout = false;
700 save_ardour_state ();
706 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
708 if (have_configure_timeout) {
709 last_configure_time = get_microseconds();
711 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
712 have_configure_timeout = true;
719 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
721 const XMLProperty* prop;
723 if ((prop = node.property ("roll")) != 0) {
724 roll_controllable->set_id (prop->value());
726 if ((prop = node.property ("stop")) != 0) {
727 stop_controllable->set_id (prop->value());
729 if ((prop = node.property ("goto-start")) != 0) {
730 goto_start_controllable->set_id (prop->value());
732 if ((prop = node.property ("goto-end")) != 0) {
733 goto_end_controllable->set_id (prop->value());
735 if ((prop = node.property ("auto-loop")) != 0) {
736 auto_loop_controllable->set_id (prop->value());
738 if ((prop = node.property ("play-selection")) != 0) {
739 play_selection_controllable->set_id (prop->value());
741 if ((prop = node.property ("rec")) != 0) {
742 rec_controllable->set_id (prop->value());
744 if ((prop = node.property ("shuttle")) != 0) {
745 shuttle_box->controllable()->set_id (prop->value());
750 ARDOUR_UI::get_transport_controllable_state ()
752 XMLNode* node = new XMLNode(X_("TransportControllables"));
755 roll_controllable->id().print (buf, sizeof (buf));
756 node->add_property (X_("roll"), buf);
757 stop_controllable->id().print (buf, sizeof (buf));
758 node->add_property (X_("stop"), buf);
759 goto_start_controllable->id().print (buf, sizeof (buf));
760 node->add_property (X_("goto_start"), buf);
761 goto_end_controllable->id().print (buf, sizeof (buf));
762 node->add_property (X_("goto_end"), buf);
763 auto_loop_controllable->id().print (buf, sizeof (buf));
764 node->add_property (X_("auto_loop"), buf);
765 play_selection_controllable->id().print (buf, sizeof (buf));
766 node->add_property (X_("play_selection"), buf);
767 rec_controllable->id().print (buf, sizeof (buf));
768 node->add_property (X_("rec"), buf);
769 shuttle_box->controllable()->id().print (buf, sizeof (buf));
770 node->add_property (X_("shuttle"), buf);
776 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
779 _session->save_state (snapshot_name);
784 ARDOUR_UI::autosave_session ()
786 if (g_main_depth() > 1) {
787 /* inside a recursive main loop,
788 give up because we may not be able to
794 if (!Config->get_periodic_safety_backups()) {
799 _session->maybe_write_autosave();
806 ARDOUR_UI::session_dirty_changed ()
813 ARDOUR_UI::update_autosave ()
815 if (_session && _session->dirty()) {
816 if (_autosave_connection.connected()) {
817 _autosave_connection.disconnect();
820 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
821 Config->get_periodic_safety_backup_interval() * 1000);
824 if (_autosave_connection.connected()) {
825 _autosave_connection.disconnect();
831 ARDOUR_UI::check_announcements ()
834 string _annc_filename;
837 _annc_filename = PROGRAM_NAME "_announcements_osx_";
838 #elif defined PLATFORM_WINDOWS
839 _annc_filename = PROGRAM_NAME "_announcements_windows_";
841 _annc_filename = PROGRAM_NAME "_announcements_linux_";
843 _annc_filename.append (VERSIONSTRING);
845 _announce_string = "";
847 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
848 FILE* fin = g_fopen (path.c_str(), "rb");
850 while (!feof (fin)) {
853 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
856 _announce_string.append (tmp, len);
861 pingback (VERSIONSTRING, path);
866 _hide_splash (gpointer arg)
868 ((ARDOUR_UI*)arg)->hide_splash();
873 ARDOUR_UI::starting ()
875 Application* app = Application::instance ();
877 bool brand_new_user = ArdourStartup::required ();
879 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
880 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
882 if (ARDOUR_COMMAND_LINE::check_announcements) {
883 check_announcements ();
888 /* we need to create this early because it may need to set the
889 * audio backend end up.
893 audio_midi_setup.get (true);
895 std::cerr << "audio-midi engine setup failed."<< std::endl;
899 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
900 nsm = new NSM_Client;
901 if (!nsm->init (nsm_url)) {
902 /* the ardour executable may have different names:
904 * waf's obj.target for distro versions: eg ardour4, ardourvst4
905 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
906 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
908 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
910 const char *process_name = g_getenv ("ARDOUR_SELF");
911 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
914 // wait for announce reply from nsm server
915 for ( i = 0; i < 5000; ++i) {
919 if (nsm->is_active()) {
924 error << _("NSM server did not announce itself") << endmsg;
927 // wait for open command from nsm server
928 for ( i = 0; i < 5000; ++i) {
931 if (nsm->client_id ()) {
937 error << _("NSM: no client ID provided") << endmsg;
941 if (_session && nsm) {
942 _session->set_nsm_state( nsm->is_active() );
944 error << _("NSM: no session created") << endmsg;
948 // nsm requires these actions disabled
949 vector<string> action_names;
950 action_names.push_back("SaveAs");
951 action_names.push_back("Rename");
952 action_names.push_back("New");
953 action_names.push_back("Open");
954 action_names.push_back("Recent");
955 action_names.push_back("Close");
957 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
958 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
960 act->set_sensitive (false);
967 error << _("NSM: initialization failed") << endmsg;
973 if (brand_new_user) {
974 _initial_verbose_plugin_scan = true;
979 _initial_verbose_plugin_scan = false;
980 switch (s.response ()) {
981 case Gtk::RESPONSE_OK:
988 #ifdef NO_PLUGIN_STATE
990 ARDOUR::RecentSessions rs;
991 ARDOUR::read_recent_sessions (rs);
993 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
995 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
997 /* already used Ardour, have sessions ... warn about plugin state */
999 ArdourDialog d (_("Free/Demo Version Warning"), true);
1001 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1002 CheckButton c (_("Don't warn me about this again"));
1004 l.set_markup (string_compose (_("<span weight=\"bold\" size=\"large\">%1</span>\n\n<b>%2</b>\n\n<i>%3</i>\n\n%4"),
1005 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1006 _("It will not restore OR save any plugin settings"),
1007 _("If you load an existing session with plugin settings\n"
1008 "they will not be used and will be lost."),
1009 _("To get full access to updates without this limitation\n"
1010 "consider becoming a subscriber for a low cost every month.")));
1011 l.set_justify (JUSTIFY_CENTER);
1013 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1015 d.get_vbox()->pack_start (l, true, true);
1016 d.get_vbox()->pack_start (b, false, false, 12);
1017 d.get_vbox()->pack_start (c, false, false, 12);
1019 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1020 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1024 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1026 if (d.run () != RESPONSE_OK) {
1032 /* go get a session */
1034 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1036 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1037 std::cerr << "Cannot get session parameters."<< std::endl;
1044 WM::Manager::instance().show_visible ();
1046 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1047 * editor window, and we may want stuff to be hidden.
1049 _status_bar_visibility.update ();
1051 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1053 if (splash && splash->is_visible()) {
1054 // in 1 second, hide the splash screen
1055 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1058 /* all other dialogs are created conditionally */
1064 ARDOUR_UI::check_memory_locking ()
1066 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1067 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1071 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1073 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1075 struct rlimit limits;
1077 long pages, page_size;
1079 size_t pages_len=sizeof(pages);
1080 if ((page_size = getpagesize()) < 0 ||
1081 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1083 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1088 ram = (int64_t) pages * (int64_t) page_size;
1091 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1095 if (limits.rlim_cur != RLIM_INFINITY) {
1097 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1101 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1102 "This might cause %1 to run out of memory before your system "
1103 "runs out of memory. \n\n"
1104 "You can view the memory limit with 'ulimit -l', "
1105 "and it is normally controlled by %2"),
1108 X_("/etc/login.conf")
1110 X_(" /etc/security/limits.conf")
1114 msg.set_default_response (RESPONSE_OK);
1116 VBox* vbox = msg.get_vbox();
1118 CheckButton cb (_("Do not show this window again"));
1119 hbox.pack_start (cb, true, false);
1120 vbox->pack_start (hbox);
1125 pop_back_splash (msg);
1129 if (cb.get_active()) {
1130 XMLNode node (X_("no-memory-warning"));
1131 Config->add_instant_xml (node);
1136 #endif // !__APPLE__
1141 ARDOUR_UI::queue_finish ()
1143 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1147 ARDOUR_UI::idle_finish ()
1150 return false; /* do not call again */
1157 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1159 if (_session->dirty()) {
1160 vector<string> actions;
1161 actions.push_back (_("Don't quit"));
1162 actions.push_back (_("Just quit"));
1163 actions.push_back (_("Save and quit"));
1164 switch (ask_about_saving_session(actions)) {
1169 /* use the default name */
1170 if (save_state_canfail ("")) {
1171 /* failed - don't quit */
1172 MessageDialog msg (_main_window,
1173 string_compose (_("\
1174 %1 was unable to save your session.\n\n\
1175 If you still wish to quit, please use the\n\n\
1176 \"Just quit\" option."), PROGRAM_NAME));
1177 pop_back_splash(msg);
1187 second_connection.disconnect ();
1188 point_one_second_connection.disconnect ();
1189 point_zero_something_second_connection.disconnect();
1190 fps_connection.disconnect();
1193 delete ARDOUR_UI::instance()->video_timeline;
1194 ARDOUR_UI::instance()->video_timeline = NULL;
1195 stop_video_server();
1197 /* Save state before deleting the session, as that causes some
1198 windows to be destroyed before their visible state can be
1201 save_ardour_state ();
1203 close_all_dialogs ();
1206 _session->set_clean ();
1207 _session->remove_pending_capture_state ();
1212 halt_connection.disconnect ();
1213 AudioEngine::instance()->stop ();
1214 #ifdef WINDOWS_VST_SUPPORT
1215 fst_stop_threading();
1221 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1223 ArdourDialog window (_("Unsaved Session"));
1224 Gtk::HBox dhbox; // the hbox for the image and text
1225 Gtk::Label prompt_label;
1226 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1230 assert (actions.size() >= 3);
1232 window.add_button (actions[0], RESPONSE_REJECT);
1233 window.add_button (actions[1], RESPONSE_APPLY);
1234 window.add_button (actions[2], RESPONSE_ACCEPT);
1236 window.set_default_response (RESPONSE_ACCEPT);
1238 Gtk::Button noquit_button (msg);
1239 noquit_button.set_name ("EditorGTKButton");
1243 if (_session->snap_name() == _session->name()) {
1244 prompt = string_compose(_("The session \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1245 _session->snap_name());
1247 prompt = string_compose(_("The snapshot \"%1\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
1248 _session->snap_name());
1251 prompt_label.set_text (prompt);
1252 prompt_label.set_name (X_("PrompterLabel"));
1253 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1255 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1256 dhbox.set_homogeneous (false);
1257 dhbox.pack_start (*dimage, false, false, 5);
1258 dhbox.pack_start (prompt_label, true, false, 5);
1259 window.get_vbox()->pack_start (dhbox);
1261 window.set_name (_("Prompter"));
1262 window.set_modal (true);
1263 window.set_resizable (false);
1266 prompt_label.show();
1271 ResponseType r = (ResponseType) window.run();
1276 case RESPONSE_ACCEPT: // save and get out of here
1278 case RESPONSE_APPLY: // get out of here
1289 ARDOUR_UI::every_second ()
1292 update_xrun_count ();
1293 update_buffer_load ();
1294 update_disk_space ();
1295 update_timecode_format ();
1296 update_peak_thread_work ();
1298 if (nsm && nsm->is_active ()) {
1301 if (!_was_dirty && _session->dirty ()) {
1305 else if (_was_dirty && !_session->dirty ()){
1313 ARDOUR_UI::every_point_one_seconds ()
1315 // TODO get rid of this..
1316 // ShuttleControl is updated directly via TransportStateChange signal
1320 ARDOUR_UI::every_point_zero_something_seconds ()
1322 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1324 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1325 float mpeak = editor_meter->update_meters();
1326 if (mpeak > editor_meter_max_peak) {
1327 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1328 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1335 ARDOUR_UI::set_fps_timeout_connection ()
1337 unsigned int interval = 40;
1338 if (!_session) return;
1339 if (_session->timecode_frames_per_second() != 0) {
1340 /* ideally we'll use a select() to sleep and not accumulate
1341 * idle time to provide a regular periodic signal.
1342 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1343 * However, that'll require a dedicated thread and cross-thread
1344 * signals to the GUI Thread..
1346 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1347 * _session->frame_rate() / _session->nominal_frame_rate()
1348 / _session->timecode_frames_per_second()
1350 #ifdef PLATFORM_WINDOWS
1351 // the smallest windows scheduler time-slice is ~15ms.
1352 // periodic GUI timeouts shorter than that will cause
1353 // WaitForSingleObject to spinlock (100% of one CPU Core)
1354 // and gtk never enters idle mode.
1355 // also changing timeBeginPeriod(1) does not affect that in
1356 // any beneficial way, so we just limit the max rate for now.
1357 interval = std::max(30u, interval); // at most ~33Hz.
1359 interval = std::max(8u, interval); // at most 120Hz.
1362 fps_connection.disconnect();
1363 Timers::set_fps_interval (interval);
1367 ARDOUR_UI::update_sample_rate (framecnt_t)
1371 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1373 if (!AudioEngine::instance()->connected()) {
1375 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1379 framecnt_t rate = AudioEngine::instance()->sample_rate();
1382 /* no sample rate available */
1383 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1386 if (fmod (rate, 1000.0) != 0.0) {
1387 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1388 (float) rate / 1000.0f,
1389 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1391 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1393 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1397 sample_rate_label.set_markup (buf);
1401 ARDOUR_UI::update_format ()
1404 format_label.set_text ("");
1409 s << _("File:") << X_(" <span foreground=\"green\">");
1411 switch (_session->config.get_native_file_header_format ()) {
1443 switch (_session->config.get_native_file_data_format ()) {
1457 format_label.set_markup (s.str ());
1461 ARDOUR_UI::update_xrun_count ()
1465 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1466 should also be changed.
1470 const unsigned int x = _session->get_xrun_count ();
1472 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1474 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1477 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1479 xrun_label.set_markup (buf);
1480 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1484 ARDOUR_UI::update_cpu_load ()
1488 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1489 should also be changed.
1492 double const c = AudioEngine::instance()->get_dsp_load ();
1493 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1494 cpu_load_label.set_markup (buf);
1498 ARDOUR_UI::update_peak_thread_work ()
1501 const int c = SourceFactory::peak_work_queue_length ();
1503 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1504 peak_thread_work_label.set_markup (buf);
1506 peak_thread_work_label.set_markup (X_(""));
1511 ARDOUR_UI::update_buffer_load ()
1515 uint32_t const playback = _session ? _session->playback_load () : 100;
1516 uint32_t const capture = _session ? _session->capture_load () : 100;
1518 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1519 should also be changed.
1525 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1526 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1527 playback <= 5 ? X_("red") : X_("green"),
1529 capture <= 5 ? X_("red") : X_("green"),
1533 buffer_load_label.set_markup (buf);
1535 buffer_load_label.set_text ("");
1540 ARDOUR_UI::count_recenabled_streams (Route& route)
1542 Track* track = dynamic_cast<Track*>(&route);
1543 if (track && track->record_enabled()) {
1544 rec_enabled_streams += track->n_inputs().n_total();
1549 ARDOUR_UI::update_disk_space()
1551 if (_session == 0) {
1555 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1557 framecnt_t fr = _session->frame_rate();
1560 /* skip update - no SR available */
1565 /* Available space is unknown */
1566 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1567 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1568 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1570 rec_enabled_streams = 0;
1571 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1573 framecnt_t frames = opt_frames.get_value_or (0);
1575 if (rec_enabled_streams) {
1576 frames /= rec_enabled_streams;
1583 hrs = frames / (fr * 3600);
1586 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1588 frames -= hrs * fr * 3600;
1589 mins = frames / (fr * 60);
1590 frames -= mins * fr * 60;
1593 bool const low = (hrs == 0 && mins <= 30);
1597 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1598 low ? X_("red") : X_("green"),
1604 disk_space_label.set_markup (buf);
1608 ARDOUR_UI::update_timecode_format ()
1614 TimecodeSlave* tcslave;
1615 SyncSource sync_src = Config->get_sync_source();
1617 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1618 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1623 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1624 matching ? X_("green") : X_("red"),
1625 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1627 snprintf (buf, sizeof (buf), "TC: n/a");
1630 timecode_format_label.set_markup (buf);
1634 ARDOUR_UI::update_wall_clock ()
1638 static int last_min = -1;
1641 tm_now = localtime (&now);
1642 if (last_min != tm_now->tm_min) {
1644 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1645 wall_clock_label.set_text (buf);
1646 last_min = tm_now->tm_min;
1653 ARDOUR_UI::open_recent_session ()
1655 bool can_return = (_session != 0);
1657 SessionDialog recent_session_dialog;
1661 ResponseType r = (ResponseType) recent_session_dialog.run ();
1664 case RESPONSE_ACCEPT:
1668 recent_session_dialog.hide();
1675 recent_session_dialog.hide();
1679 std::string path = recent_session_dialog.session_folder();
1680 std::string state = recent_session_dialog.session_name (should_be_new);
1682 if (should_be_new == true) {
1686 _session_is_new = false;
1688 if (load_session (path, state) == 0) {
1697 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1699 if (!AudioEngine::instance()->connected()) {
1700 MessageDialog msg (parent, string_compose (
1701 _("%1 is not connected to any audio backend.\n"
1702 "You cannot open or close sessions in this condition"),
1704 pop_back_splash (msg);
1712 ARDOUR_UI::open_session ()
1714 if (!check_audioengine (_main_window)) {
1718 /* ardour sessions are folders */
1719 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1720 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1721 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1722 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1725 string session_parent_dir = Glib::path_get_dirname(_session->path());
1726 open_session_selector.set_current_folder(session_parent_dir);
1728 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1731 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1733 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1734 string default_session_folder = Config->get_default_session_parent_dir();
1735 open_session_selector.add_shortcut_folder (default_session_folder);
1737 catch (Glib::Error & e) {
1738 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1741 FileFilter session_filter;
1742 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1743 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1744 open_session_selector.add_filter (session_filter);
1745 open_session_selector.set_filter (session_filter);
1747 int response = open_session_selector.run();
1748 open_session_selector.hide ();
1750 if (response == Gtk::RESPONSE_CANCEL) {
1754 string session_path = open_session_selector.get_filename();
1758 if (session_path.length() > 0) {
1759 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1760 _session_is_new = isnew;
1761 load_session (path, name);
1768 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1769 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1771 list<boost::shared_ptr<MidiTrack> > tracks;
1773 if (_session == 0) {
1774 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1779 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1781 if (tracks.size() != how_many) {
1782 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1787 MessageDialog msg (_main_window,
1788 string_compose (_("There are insufficient ports available\n\
1789 to create a new track or bus.\n\
1790 You should save %1, exit and\n\
1791 restart with more ports."), PROGRAM_NAME));
1798 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1800 ChanCount one_midi_channel;
1801 one_midi_channel.set (DataType::MIDI, 1);
1804 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1809 ARDOUR_UI::session_add_audio_route (
1811 int32_t input_channels,
1812 int32_t output_channels,
1813 ARDOUR::TrackMode mode,
1814 RouteGroup* route_group,
1816 string const & name_template
1819 list<boost::shared_ptr<AudioTrack> > tracks;
1822 if (_session == 0) {
1823 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1829 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1831 if (tracks.size() != how_many) {
1832 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1838 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1840 if (routes.size() != how_many) {
1841 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1848 MessageDialog msg (_main_window,
1849 string_compose (_("There are insufficient ports available\n\
1850 to create a new track or bus.\n\
1851 You should save %1, exit and\n\
1852 restart with more ports."), PROGRAM_NAME));
1853 pop_back_splash (msg);
1859 ARDOUR_UI::transport_goto_start ()
1862 _session->goto_start();
1864 /* force displayed area in editor to start no matter
1865 what "follow playhead" setting is.
1869 editor->center_screen (_session->current_start_frame ());
1875 ARDOUR_UI::transport_goto_zero ()
1878 _session->request_locate (0);
1880 /* force displayed area in editor to start no matter
1881 what "follow playhead" setting is.
1885 editor->reset_x_origin (0);
1891 ARDOUR_UI::transport_goto_wallclock ()
1893 if (_session && editor) {
1900 localtime_r (&now, &tmnow);
1902 framecnt_t frame_rate = _session->frame_rate();
1904 if (frame_rate == 0) {
1905 /* no frame rate available */
1909 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1910 frames += tmnow.tm_min * (60 * frame_rate);
1911 frames += tmnow.tm_sec * frame_rate;
1913 _session->request_locate (frames, _session->transport_rolling ());
1915 /* force displayed area in editor to start no matter
1916 what "follow playhead" setting is.
1920 editor->center_screen (frames);
1926 ARDOUR_UI::transport_goto_end ()
1929 framepos_t const frame = _session->current_end_frame();
1930 _session->request_locate (frame);
1932 /* force displayed area in editor to start no matter
1933 what "follow playhead" setting is.
1937 editor->center_screen (frame);
1943 ARDOUR_UI::transport_stop ()
1949 if (_session->is_auditioning()) {
1950 _session->cancel_audition ();
1954 _session->request_stop (false, true);
1957 /** Check if any tracks are record enabled. If none are, record enable all of them.
1958 * @return true if track record-enabled status was changed, false otherwise.
1961 ARDOUR_UI::trx_record_enable_all_tracks ()
1967 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1968 bool none_record_enabled = true;
1970 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1971 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1974 if (t->record_enabled()) {
1975 none_record_enabled = false;
1980 if (none_record_enabled) {
1981 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1984 return none_record_enabled;
1988 ARDOUR_UI::transport_record (bool roll)
1991 switch (_session->record_status()) {
1992 case Session::Disabled:
1993 if (_session->ntracks() == 0) {
1994 MessageDialog msg (_main_window, _("Please create one or more tracks before trying to record.\nYou can do this with the \"Add Track or Bus\" option in the Session menu."));
1998 if (Profile->get_trx()) {
1999 roll = trx_record_enable_all_tracks ();
2001 _session->maybe_enable_record ();
2006 case Session::Recording:
2008 _session->request_stop();
2010 _session->disable_record (false, true);
2014 case Session::Enabled:
2015 _session->disable_record (false, true);
2021 ARDOUR_UI::transport_roll ()
2027 if (_session->is_auditioning()) {
2032 if (_session->config.get_external_sync()) {
2033 switch (Config->get_sync_source()) {
2037 /* transport controlled by the master */
2043 bool rolling = _session->transport_rolling();
2045 if (_session->get_play_loop()) {
2047 /* If loop playback is not a mode, then we should cancel
2048 it when this action is requested. If it is a mode
2049 we just leave it in place.
2052 if (!Config->get_loop_is_mode()) {
2053 /* XXX it is not possible to just leave seamless loop and keep
2054 playing at present (nov 4th 2009)
2056 if (!Config->get_seamless_loop()) {
2057 /* stop loop playback and stop rolling */
2058 _session->request_play_loop (false, true);
2059 } else if (rolling) {
2060 /* stop loop playback but keep rolling */
2061 _session->request_play_loop (false, false);
2065 } else if (_session->get_play_range () ) {
2066 /* stop playing a range if we currently are */
2067 _session->request_play_range (0, true);
2071 _session->request_transport_speed (1.0f);
2076 ARDOUR_UI::get_smart_mode() const
2078 return ( editor->get_smart_mode() );
2083 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2089 if (_session->is_auditioning()) {
2090 _session->cancel_audition ();
2094 if (_session->config.get_external_sync()) {
2095 switch (Config->get_sync_source()) {
2099 /* transport controlled by the master */
2104 bool rolling = _session->transport_rolling();
2105 bool affect_transport = true;
2107 if (rolling && roll_out_of_bounded_mode) {
2108 /* drop out of loop/range playback but leave transport rolling */
2109 if (_session->get_play_loop()) {
2110 if (_session->actively_recording()) {
2112 /* just stop using the loop, then actually stop
2115 _session->request_play_loop (false, affect_transport);
2118 if (Config->get_seamless_loop()) {
2119 /* the disk buffers contain copies of the loop - we can't
2120 just keep playing, so stop the transport. the user
2121 can restart as they wish.
2123 affect_transport = true;
2125 /* disk buffers are normal, so we can keep playing */
2126 affect_transport = false;
2128 _session->request_play_loop (false, affect_transport);
2130 } else if (_session->get_play_range ()) {
2131 affect_transport = false;
2132 _session->request_play_range (0, true);
2136 if (affect_transport) {
2138 _session->request_stop (with_abort, true);
2140 /* the only external sync condition we can be in here
2141 * would be Engine (JACK) sync, in which case we still
2145 if (UIConfiguration::instance().get_follow_edits() && ( editor->get_selection().time.front().start == _session->transport_frame() ) ) { //if playhead is exactly at the start of a range, we can assume it was placed there by follow_edits
2146 _session->request_play_range (&editor->get_selection().time, true);
2147 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2149 _session->request_transport_speed (1.0f);
2155 ARDOUR_UI::toggle_session_auto_loop ()
2161 Location * looploc = _session->locations()->auto_loop_location();
2167 if (_session->get_play_loop()) {
2169 /* looping enabled, our job is to disable it */
2171 _session->request_play_loop (false);
2175 /* looping not enabled, our job is to enable it.
2177 loop-is-NOT-mode: this action always starts the transport rolling.
2178 loop-IS-mode: this action simply sets the loop play mechanism, but
2179 does not start transport.
2181 if (Config->get_loop_is_mode()) {
2182 _session->request_play_loop (true, false);
2184 _session->request_play_loop (true, true);
2188 //show the loop markers
2189 looploc->set_hidden (false, this);
2193 ARDOUR_UI::transport_play_selection ()
2199 editor->play_selection ();
2203 ARDOUR_UI::transport_play_preroll ()
2208 editor->play_with_preroll ();
2212 ARDOUR_UI::transport_rewind (int option)
2214 float current_transport_speed;
2217 current_transport_speed = _session->transport_speed();
2219 if (current_transport_speed >= 0.0f) {
2222 _session->request_transport_speed (-1.0f);
2225 _session->request_transport_speed (-4.0f);
2228 _session->request_transport_speed (-0.5f);
2233 _session->request_transport_speed (current_transport_speed * 1.5f);
2239 ARDOUR_UI::transport_forward (int option)
2245 float current_transport_speed = _session->transport_speed();
2247 if (current_transport_speed <= 0.0f) {
2250 _session->request_transport_speed (1.0f);
2253 _session->request_transport_speed (4.0f);
2256 _session->request_transport_speed (0.5f);
2261 _session->request_transport_speed (current_transport_speed * 1.5f);
2266 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2272 boost::shared_ptr<Route> r;
2274 if ((r = _session->route_by_remote_id (rid)) != 0) {
2276 boost::shared_ptr<Track> t;
2278 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2279 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2285 ARDOUR_UI::map_transport_state ()
2288 auto_loop_button.unset_active_state ();
2289 play_selection_button.unset_active_state ();
2290 roll_button.unset_active_state ();
2291 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2295 shuttle_box->map_transport_state ();
2297 float sp = _session->transport_speed();
2303 if (_session->get_play_range()) {
2305 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2306 roll_button.unset_active_state ();
2307 auto_loop_button.unset_active_state ();
2309 } else if (_session->get_play_loop ()) {
2311 auto_loop_button.set_active (true);
2312 play_selection_button.set_active (false);
2313 if (Config->get_loop_is_mode()) {
2314 roll_button.set_active (true);
2316 roll_button.set_active (false);
2321 roll_button.set_active (true);
2322 play_selection_button.set_active (false);
2323 auto_loop_button.set_active (false);
2326 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2327 /* light up both roll and play-selection if they are joined */
2328 roll_button.set_active (true);
2329 play_selection_button.set_active (true);
2332 stop_button.set_active (false);
2336 stop_button.set_active (true);
2337 roll_button.set_active (false);
2338 play_selection_button.set_active (false);
2339 if (Config->get_loop_is_mode ()) {
2340 auto_loop_button.set_active (_session->get_play_loop());
2342 auto_loop_button.set_active (false);
2344 update_disk_space ();
2349 ARDOUR_UI::blink_handler (bool blink_on)
2351 transport_rec_enable_blink (blink_on);
2352 solo_blink (blink_on);
2353 sync_blink (blink_on);
2354 audition_blink (blink_on);
2355 feedback_blink (blink_on);
2356 error_blink (blink_on);
2360 ARDOUR_UI::update_clocks ()
2362 if (!_session) return;
2364 if (editor && !editor->dragging_playhead()) {
2365 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2370 ARDOUR_UI::start_clocking ()
2372 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2373 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2375 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2380 ARDOUR_UI::stop_clocking ()
2382 clock_signal_connection.disconnect ();
2386 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2390 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2392 label->set_text (buf);
2393 bar->set_fraction (fraction);
2395 /* process events, redraws, etc. */
2397 while (gtk_events_pending()) {
2398 gtk_main_iteration ();
2401 return true; /* continue with save-as */
2405 ARDOUR_UI::save_session_as ()
2411 if (!save_as_dialog) {
2412 save_as_dialog = new SaveAsDialog;
2415 save_as_dialog->set_name (_session->name());
2417 int response = save_as_dialog->run ();
2419 save_as_dialog->hide ();
2422 case Gtk::RESPONSE_OK:
2431 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2432 sa.new_name = save_as_dialog->new_name ();
2433 sa.switch_to = save_as_dialog->switch_to();
2434 sa.copy_media = save_as_dialog->copy_media();
2435 sa.copy_external = save_as_dialog->copy_external();
2436 sa.include_media = save_as_dialog->include_media ();
2438 /* Only bother with a progress dialog if we're going to copy
2439 media into the save-as target. Without that choice, this
2440 will be very fast because we're only talking about a few kB's to
2441 perhaps a couple of MB's of data.
2444 ArdourDialog progress_dialog (_("Save As"), true);
2446 if (sa.include_media && sa.copy_media) {
2449 Gtk::ProgressBar progress_bar;
2451 progress_dialog.get_vbox()->pack_start (label);
2452 progress_dialog.get_vbox()->pack_start (progress_bar);
2454 progress_bar.show ();
2456 /* this signal will be emitted from within this, the calling thread,
2457 * after every file is copied. It provides information on percentage
2458 * complete (in terms of total data to copy), the number of files
2459 * copied so far, and the total number to copy.
2464 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2466 progress_dialog.show_all ();
2467 progress_dialog.present ();
2470 if (_session->save_as (sa)) {
2472 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2476 if (!sa.include_media) {
2477 unload_session (false);
2478 load_session (sa.final_session_folder_name, sa.new_name);
2483 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2487 struct tm local_time;
2490 localtime_r (&n, &local_time);
2491 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2493 save_state (timebuf, switch_to_it);
2498 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2502 prompter.get_result (snapname);
2504 bool do_save = (snapname.length() != 0);
2507 char illegal = Session::session_name_is_legal(snapname);
2509 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2510 "snapshot names may not contain a '%1' character"), illegal));
2516 vector<std::string> p;
2517 get_state_files_in_directory (_session->session_directory().root_path(), p);
2518 vector<string> n = get_file_names_no_extension (p);
2520 if (find (n.begin(), n.end(), snapname) != n.end()) {
2522 do_save = overwrite_file_dialog (prompter,
2523 _("Confirm Snapshot Overwrite"),
2524 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2528 save_state (snapname, switch_to_it);
2538 /** Ask the user for the name of a new snapshot and then take it.
2542 ARDOUR_UI::snapshot_session (bool switch_to_it)
2544 ArdourPrompter prompter (true);
2546 prompter.set_name ("Prompter");
2547 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2549 prompter.set_title (_("Save as..."));
2550 prompter.set_prompt (_("New session name"));
2552 prompter.set_title (_("Take Snapshot"));
2553 prompter.set_prompt (_("Name of new snapshot"));
2557 prompter.set_initial_text (_session->snap_name());
2561 struct tm local_time;
2564 localtime_r (&n, &local_time);
2565 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2566 prompter.set_initial_text (timebuf);
2569 bool finished = false;
2571 switch (prompter.run()) {
2572 case RESPONSE_ACCEPT:
2574 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2585 /** Ask the user for a new session name and then rename the session to it.
2589 ARDOUR_UI::rename_session ()
2595 ArdourPrompter prompter (true);
2598 prompter.set_name ("Prompter");
2599 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2600 prompter.set_title (_("Rename Session"));
2601 prompter.set_prompt (_("New session name"));
2604 switch (prompter.run()) {
2605 case RESPONSE_ACCEPT:
2607 prompter.get_result (name);
2609 bool do_rename = (name.length() != 0);
2612 char illegal = Session::session_name_is_legal (name);
2615 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2616 "session names may not contain a '%1' character"), illegal));
2621 switch (_session->rename (name)) {
2623 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2624 msg.set_position (WIN_POS_MOUSE);
2632 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2633 msg.set_position (WIN_POS_MOUSE);
2649 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2651 if (!_session || _session->deletion_in_progress()) {
2655 XMLNode* node = new XMLNode (X_("UI"));
2657 WM::Manager::instance().add_state (*node);
2659 node->add_child_nocopy (gui_object_state->get_state());
2661 _session->add_extra_xml (*node);
2663 if (export_video_dialog) {
2664 _session->add_extra_xml (export_video_dialog->get_state());
2667 save_state_canfail (name, switch_to_it);
2671 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2676 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2681 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2686 ARDOUR_UI::primary_clock_value_changed ()
2689 _session->request_locate (primary_clock->current_time ());
2694 ARDOUR_UI::big_clock_value_changed ()
2697 _session->request_locate (big_clock->current_time ());
2702 ARDOUR_UI::secondary_clock_value_changed ()
2705 _session->request_locate (secondary_clock->current_time ());
2710 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2712 if (_session == 0) {
2716 if (_session->step_editing()) {
2720 Session::RecordState const r = _session->record_status ();
2721 bool const h = _session->have_rec_enabled_track ();
2723 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2725 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2727 rec_button.set_active_state (Gtkmm2ext::Off);
2729 } else if (r == Session::Recording && h) {
2730 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2732 rec_button.unset_active_state ();
2737 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2741 prompter.get_result (name);
2743 if (name.length()) {
2744 int failed = _session->save_template (name);
2746 if (failed == -2) { /* file already exists. */
2747 bool overwrite = overwrite_file_dialog (prompter,
2748 _("Confirm Template Overwrite"),
2749 _("A template already exists with that name. Do you want to overwrite it?"));
2752 _session->save_template (name, true);
2764 ARDOUR_UI::save_template ()
2766 ArdourPrompter prompter (true);
2768 if (!check_audioengine (_main_window)) {
2772 prompter.set_name (X_("Prompter"));
2773 prompter.set_title (_("Save Template"));
2774 prompter.set_prompt (_("Name for template:"));
2775 prompter.set_initial_text(_session->name() + _("-template"));
2776 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2778 bool finished = false;
2780 switch (prompter.run()) {
2781 case RESPONSE_ACCEPT:
2782 finished = process_save_template_prompter (prompter);
2793 ARDOUR_UI::edit_metadata ()
2795 SessionMetadataEditor dialog;
2796 dialog.set_session (_session);
2797 dialog.grab_focus ();
2802 ARDOUR_UI::import_metadata ()
2804 SessionMetadataImporter dialog;
2805 dialog.set_session (_session);
2810 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2812 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2814 MessageDialog msg (str,
2816 Gtk::MESSAGE_WARNING,
2817 Gtk::BUTTONS_YES_NO,
2821 msg.set_name (X_("OpenExistingDialog"));
2822 msg.set_title (_("Open Existing Session"));
2823 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2824 msg.set_position (Gtk::WIN_POS_CENTER);
2825 pop_back_splash (msg);
2827 switch (msg.run()) {
2836 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2838 BusProfile bus_profile;
2842 bus_profile.master_out_channels = 2;
2843 bus_profile.input_ac = AutoConnectPhysical;
2844 bus_profile.output_ac = AutoConnectMaster;
2845 bus_profile.requested_physical_in = 0; // use all available
2846 bus_profile.requested_physical_out = 0; // use all available
2850 /* get settings from advanced section of NSD */
2852 if (sd.create_master_bus()) {
2853 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2855 bus_profile.master_out_channels = 0;
2858 if (sd.connect_inputs()) {
2859 bus_profile.input_ac = AutoConnectPhysical;
2861 bus_profile.input_ac = AutoConnectOption (0);
2864 bus_profile.output_ac = AutoConnectOption (0);
2866 if (sd.connect_outputs ()) {
2867 if (sd.connect_outs_to_master()) {
2868 bus_profile.output_ac = AutoConnectMaster;
2869 } else if (sd.connect_outs_to_physical()) {
2870 bus_profile.output_ac = AutoConnectPhysical;
2874 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2875 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2878 if (build_session (session_path, session_name, bus_profile)) {
2886 ARDOUR_UI::load_from_application_api (const std::string& path)
2888 ARDOUR_COMMAND_LINE::session_name = path;
2889 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2891 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2893 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2894 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2895 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2896 * -> SessionDialog is not displayed
2899 if (_session_dialog) {
2900 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2901 std::string session_path = path;
2902 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2903 session_path = Glib::path_get_dirname (session_path);
2905 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2906 _session_dialog->set_provided_session (session_name, session_path);
2907 _session_dialog->response (RESPONSE_NONE);
2908 _session_dialog->hide();
2913 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2914 /* /path/to/foo => /path/to/foo, foo */
2915 rv = load_session (path, basename_nosuffix (path));
2917 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2918 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2921 // if load_session fails -> pop up SessionDialog.
2923 ARDOUR_COMMAND_LINE::session_name = "";
2925 if (get_session_parameters (true, false)) {
2929 goto_editor_window ();
2933 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2935 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2937 string session_name;
2938 string session_path;
2939 string template_name;
2941 bool likely_new = false;
2942 bool cancel_not_quit;
2944 /* deal with any existing DIRTY session now, rather than later. don't
2945 * treat a non-dirty session this way, so that it stays visible
2946 * as we bring up the new session dialog.
2949 if (_session && ARDOUR_UI::instance()->video_timeline) {
2950 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2953 /* if there is already a session, relabel the button
2954 on the SessionDialog so that we don't Quit directly
2956 cancel_not_quit = (_session != 0);
2958 if (_session && _session->dirty()) {
2959 if (unload_session (false)) {
2960 /* unload cancelled by user */
2963 ARDOUR_COMMAND_LINE::session_name = "";
2966 if (!load_template.empty()) {
2967 should_be_new = true;
2968 template_name = load_template;
2971 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2972 session_path = ARDOUR_COMMAND_LINE::session_name;
2974 if (!session_path.empty()) {
2975 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2976 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2977 /* session/snapshot file, change path to be dir */
2978 session_path = Glib::path_get_dirname (session_path);
2983 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2985 _session_dialog = &session_dialog;
2988 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2990 /* if they named a specific statefile, use it, otherwise they are
2991 just giving a session folder, and we want to use it as is
2992 to find the session.
2995 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2997 if (suffix != string::npos) {
2998 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2999 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3000 session_name = Glib::path_get_basename (session_name);
3002 session_path = ARDOUR_COMMAND_LINE::session_name;
3003 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3008 session_dialog.clear_given ();
3011 if (should_be_new || session_name.empty()) {
3012 /* need the dialog to get info from user */
3014 cerr << "run dialog\n";
3016 switch (session_dialog.run()) {
3017 case RESPONSE_ACCEPT:
3020 /* this is used for async * app->ShouldLoad(). */
3021 continue; // while loop
3024 if (quit_on_cancel) {
3025 // JE - Currently (July 2014) this section can only get reached if the
3026 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3027 // point does NOT indicate an abnormal termination). Therefore, let's
3028 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3030 pthread_cancel_all ();
3038 session_dialog.hide ();
3041 /* if we run the startup dialog again, offer more than just "new session" */
3043 should_be_new = false;
3045 session_name = session_dialog.session_name (likely_new);
3046 session_path = session_dialog.session_folder ();
3052 string::size_type suffix = session_name.find (statefile_suffix);
3054 if (suffix != string::npos) {
3055 session_name = session_name.substr (0, suffix);
3058 /* this shouldn't happen, but we catch it just in case it does */
3060 if (session_name.empty()) {
3064 if (session_dialog.use_session_template()) {
3065 template_name = session_dialog.session_template_name();
3066 _session_is_new = true;
3069 if (session_name[0] == G_DIR_SEPARATOR ||
3070 #ifdef PLATFORM_WINDOWS
3071 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3073 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3074 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3079 /* absolute path or cwd-relative path specified for session name: infer session folder
3080 from what was given.
3083 session_path = Glib::path_get_dirname (session_name);
3084 session_name = Glib::path_get_basename (session_name);
3088 session_path = session_dialog.session_folder();
3090 char illegal = Session::session_name_is_legal (session_name);
3093 MessageDialog msg (session_dialog,
3094 string_compose (_("To ensure compatibility with various systems\n"
3095 "session names may not contain a '%1' character"),
3098 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3103 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3106 if (likely_new && !nsm) {
3108 std::string existing = Glib::build_filename (session_path, session_name);
3110 if (!ask_about_loading_existing_session (existing)) {
3111 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3116 _session_is_new = false;
3121 pop_back_splash (session_dialog);
3122 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3124 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3128 char illegal = Session::session_name_is_legal(session_name);
3131 pop_back_splash (session_dialog);
3132 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3133 "session names may not contain a '%1' character"), illegal));
3135 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3139 _session_is_new = true;
3142 if (likely_new && template_name.empty()) {
3144 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3148 ret = load_session (session_path, session_name, template_name);
3151 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3155 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3156 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3160 /* clear this to avoid endless attempts to load the
3164 ARDOUR_COMMAND_LINE::session_name = "";
3168 _session_dialog = NULL;
3174 ARDOUR_UI::close_session()
3176 if (!check_audioengine (_main_window)) {
3180 if (unload_session (true)) {
3184 ARDOUR_COMMAND_LINE::session_name = "";
3186 if (get_session_parameters (true, false)) {
3191 /** @param snap_name Snapshot name (without .ardour suffix).
3192 * @return -2 if the load failed because we are not connected to the AudioEngine.
3195 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3197 Session *new_session;
3202 unload_status = unload_session ();
3204 if (unload_status < 0) {
3206 } else if (unload_status > 0) {
3212 session_loaded = false;
3214 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3217 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3220 /* this one is special */
3222 catch (AudioEngine::PortRegistrationFailure& err) {
3224 MessageDialog msg (err.what(),
3227 Gtk::BUTTONS_CLOSE);
3229 msg.set_title (_("Port Registration Error"));
3230 msg.set_secondary_text (_("Click the Close button to try again."));
3231 msg.set_position (Gtk::WIN_POS_CENTER);
3232 pop_back_splash (msg);
3235 int response = msg.run ();
3240 case RESPONSE_CANCEL:
3247 catch (SessionException e) {
3248 MessageDialog msg (string_compose(
3249 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3250 path, snap_name, e.what()),
3255 msg.set_title (_("Loading Error"));
3256 msg.set_position (Gtk::WIN_POS_CENTER);
3257 pop_back_splash (msg);
3269 MessageDialog msg (string_compose(
3270 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3276 msg.set_title (_("Loading Error"));
3277 msg.set_position (Gtk::WIN_POS_CENTER);
3278 pop_back_splash (msg);
3290 list<string> const u = new_session->unknown_processors ();
3292 MissingPluginDialog d (_session, u);
3297 if (!new_session->writable()) {
3298 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3303 msg.set_title (_("Read-only Session"));
3304 msg.set_position (Gtk::WIN_POS_CENTER);
3305 pop_back_splash (msg);
3312 /* Now the session been created, add the transport controls */
3313 new_session->add_controllable(roll_controllable);
3314 new_session->add_controllable(stop_controllable);
3315 new_session->add_controllable(goto_start_controllable);
3316 new_session->add_controllable(goto_end_controllable);
3317 new_session->add_controllable(auto_loop_controllable);
3318 new_session->add_controllable(play_selection_controllable);
3319 new_session->add_controllable(rec_controllable);
3321 set_session (new_session);
3323 session_loaded = true;
3326 _session->set_clean ();
3329 #ifdef WINDOWS_VST_SUPPORT
3330 fst_stop_threading();
3334 Timers::TimerSuspender t;
3338 #ifdef WINDOWS_VST_SUPPORT
3339 fst_start_threading();
3348 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3350 Session *new_session;
3353 session_loaded = false;
3354 x = unload_session ();
3362 _session_is_new = true;
3365 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3368 catch (SessionException e) {
3370 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3371 msg.set_title (_("Loading Error"));
3372 msg.set_position (Gtk::WIN_POS_CENTER);
3373 pop_back_splash (msg);
3379 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3380 msg.set_title (_("Loading Error"));
3381 msg.set_position (Gtk::WIN_POS_CENTER);
3382 pop_back_splash (msg);
3387 /* Give the new session the default GUI state, if such things exist */
3390 n = Config->instant_xml (X_("Editor"));
3392 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3393 new_session->add_instant_xml (*n, false);
3395 n = Config->instant_xml (X_("Mixer"));
3397 new_session->add_instant_xml (*n, false);
3400 /* Put the playhead at 0 and scroll fully left */
3401 n = new_session->instant_xml (X_("Editor"));
3403 n->add_property (X_("playhead"), X_("0"));
3404 n->add_property (X_("left-frame"), X_("0"));
3407 set_session (new_session);
3409 session_loaded = true;
3411 new_session->save_state(new_session->name());
3417 ARDOUR_UI::launch_chat ()
3419 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3421 dialog.set_title (_("About the Chat"));
3422 dialog.set_secondary_text (_("When you're inside the chat just ask your question and wait for an answer. The chat is occupied by real people with real lives so many of them are passively online and might not read your question before minutes or hours later.\nSo please be patient and wait for an answer.\n\nYou should just leave the chat window open and check back regularly until someone has answered your question."));
3424 switch (dialog.run()) {
3427 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3428 #elif defined PLATFORM_WINDOWS
3429 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3431 open_uri("http://webchat.freenode.net/?channels=ardour");
3440 ARDOUR_UI::launch_manual ()
3442 PBD::open_uri (Config->get_tutorial_manual_url());
3446 ARDOUR_UI::launch_reference ()
3448 PBD::open_uri (Config->get_reference_manual_url());
3452 ARDOUR_UI::launch_tracker ()
3454 PBD::open_uri ("http://tracker.ardour.org");
3458 ARDOUR_UI::launch_subscribe ()
3460 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3464 ARDOUR_UI::launch_cheat_sheet ()
3467 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3469 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3474 ARDOUR_UI::launch_website ()
3476 PBD::open_uri ("http://ardour.org");
3480 ARDOUR_UI::launch_website_dev ()
3482 PBD::open_uri ("http://ardour.org/development.html");
3486 ARDOUR_UI::launch_forums ()
3488 PBD::open_uri ("https://community.ardour.org/forums");
3492 ARDOUR_UI::launch_howto_report ()
3494 PBD::open_uri ("http://ardour.org/reporting_bugs");
3498 ARDOUR_UI::loading_message (const std::string& msg)
3500 if (ARDOUR_COMMAND_LINE::no_splash) {
3508 splash->message (msg);
3512 ARDOUR_UI::show_splash ()
3516 splash = new Splash;
3526 ARDOUR_UI::hide_splash ()
3533 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3537 removed = rep.paths.size();
3540 MessageDialog msgd (_main_window,
3541 _("No files were ready for clean-up"),
3545 msgd.set_title (_("Clean-up"));
3546 msgd.set_secondary_text (_("If this seems suprising, \n\
3547 check for any existing snapshots.\n\
3548 These may still include regions that\n\
3549 require some unused files to continue to exist."));
3555 ArdourDialog results (_("Clean-up"), true, false);
3557 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3558 CleanupResultsModelColumns() {
3562 Gtk::TreeModelColumn<std::string> visible_name;
3563 Gtk::TreeModelColumn<std::string> fullpath;
3567 CleanupResultsModelColumns results_columns;
3568 Glib::RefPtr<Gtk::ListStore> results_model;
3569 Gtk::TreeView results_display;
3571 results_model = ListStore::create (results_columns);
3572 results_display.set_model (results_model);
3573 results_display.append_column (list_title, results_columns.visible_name);
3575 results_display.set_name ("CleanupResultsList");
3576 results_display.set_headers_visible (true);
3577 results_display.set_headers_clickable (false);
3578 results_display.set_reorderable (false);
3580 Gtk::ScrolledWindow list_scroller;
3583 Gtk::HBox dhbox; // the hbox for the image and text
3584 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3585 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3587 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3589 const string dead_directory = _session->session_directory().dead_path();
3592 %1 - number of files removed
3593 %2 - location of "dead"
3594 %3 - size of files affected
3595 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3598 const char* bprefix;
3599 double space_adjusted = 0;
3601 if (rep.space < 1000) {
3603 space_adjusted = rep.space;
3604 } else if (rep.space < 1000000) {
3605 bprefix = _("kilo");
3606 space_adjusted = floorf((float)rep.space / 1000.0);
3607 } else if (rep.space < 1000000 * 1000) {
3608 bprefix = _("mega");
3609 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3611 bprefix = _("giga");
3612 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3616 txt.set_markup (string_compose (P_("\
3617 The following file was deleted from %2,\n\
3618 releasing %3 %4bytes of disk space", "\
3619 The following %1 files were deleted from %2,\n\
3620 releasing %3 %4bytes of disk space", removed),
3621 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3623 txt.set_markup (string_compose (P_("\
3624 The following file was not in use and \n\
3625 has been moved to: %2\n\n\
3626 After a restart of %5\n\n\
3627 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3628 will release an additional %3 %4bytes of disk space.\n", "\
3629 The following %1 files were not in use and \n\
3630 have been moved to: %2\n\n\
3631 After a restart of %5\n\n\
3632 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3633 will release an additional %3 %4bytes of disk space.\n", removed),
3634 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3637 dhbox.pack_start (*dimage, true, false, 5);
3638 dhbox.pack_start (txt, true, false, 5);
3640 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3641 TreeModel::Row row = *(results_model->append());
3642 row[results_columns.visible_name] = *i;
3643 row[results_columns.fullpath] = *i;
3646 list_scroller.add (results_display);
3647 list_scroller.set_size_request (-1, 150);
3648 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3650 dvbox.pack_start (dhbox, true, false, 5);
3651 dvbox.pack_start (list_scroller, true, false, 5);
3652 ddhbox.pack_start (dvbox, true, false, 5);
3654 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3655 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3656 results.set_default_response (RESPONSE_CLOSE);
3657 results.set_position (Gtk::WIN_POS_MOUSE);
3659 results_display.show();
3660 list_scroller.show();
3667 //results.get_vbox()->show();
3668 results.set_resizable (false);
3675 ARDOUR_UI::cleanup ()
3677 if (_session == 0) {
3678 /* shouldn't happen: menu item is insensitive */
3683 MessageDialog checker (_("Are you sure you want to clean-up?"),
3685 Gtk::MESSAGE_QUESTION,
3688 checker.set_title (_("Clean-up"));
3690 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3691 ALL undo/redo information will be lost if you clean-up.\n\
3692 Clean-up will move all unused files to a \"dead\" location."));
3694 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3695 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3696 checker.set_default_response (RESPONSE_CANCEL);
3698 checker.set_name (_("CleanupDialog"));
3699 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3700 checker.set_position (Gtk::WIN_POS_MOUSE);
3702 switch (checker.run()) {
3703 case RESPONSE_ACCEPT:
3709 ARDOUR::CleanupReport rep;
3711 editor->prepare_for_cleanup ();
3713 /* do not allow flush until a session is reloaded */
3715 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3717 act->set_sensitive (false);
3720 if (_session->cleanup_sources (rep)) {
3721 editor->finish_cleanup ();
3725 editor->finish_cleanup ();
3728 display_cleanup_results (rep, _("Cleaned Files"), false);
3732 ARDOUR_UI::flush_trash ()
3734 if (_session == 0) {
3735 /* shouldn't happen: menu item is insensitive */
3739 ARDOUR::CleanupReport rep;
3741 if (_session->cleanup_trash_sources (rep)) {
3745 display_cleanup_results (rep, _("deleted file"), true);
3749 ARDOUR_UI::cleanup_peakfiles ()
3751 if (_session == 0) {
3752 /* shouldn't happen: menu item is insensitive */
3756 if (! _session->can_cleanup_peakfiles ()) {
3760 // get all region-views in this session
3762 TrackViewList empty;
3764 editor->get_regions_after(rs, (framepos_t) 0, empty);
3765 std::list<RegionView*> views = rs.by_layer();
3767 // remove displayed audio-region-views waveforms
3768 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3769 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3770 if (!arv) { continue ; }
3771 arv->delete_waves();
3774 // cleanup peak files:
3775 // - stop pending peakfile threads
3776 // - close peakfiles if any
3777 // - remove peak dir in session
3778 // - setup peakfiles (background thread)
3779 _session->cleanup_peakfiles ();
3781 // re-add waves to ARV
3782 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3783 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3784 if (!arv) { continue ; }
3785 arv->create_waves();
3790 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3792 uint32_t order_hint = UINT32_MAX;
3794 if (editor->get_selection().tracks.empty()) {
3799 we want the new routes to have their order keys set starting from
3800 the highest order key in the selection + 1 (if available).
3803 if (place == AddRouteDialog::AfterSelection) {
3804 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3806 order_hint = rtav->route()->order_key();
3809 } else if (place == AddRouteDialog::BeforeSelection) {
3810 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3812 order_hint = rtav->route()->order_key();
3814 } else if (place == AddRouteDialog::First) {
3817 /* leave order_hint at UINT32_MAX */
3820 if (order_hint == UINT32_MAX) {
3821 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3822 * not setting an order hint will place new routes last.
3827 _session->set_order_hint (order_hint);
3829 /* create a gap in the existing route order keys to accomodate new routes.*/
3830 boost::shared_ptr <RouteList> rd = _session->get_routes();
3831 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3832 boost::shared_ptr<Route> rt (*ri);
3834 if (rt->is_monitor()) {
3838 if (rt->order_key () >= order_hint) {
3839 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3845 ARDOUR_UI::start_duplicate_routes ()
3847 if (!duplicate_routes_dialog) {
3848 duplicate_routes_dialog = new DuplicateRouteDialog;
3851 if (duplicate_routes_dialog->restart (_session)) {
3855 duplicate_routes_dialog->present ();
3859 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3867 if (add_route_dialog->is_visible()) {
3868 /* we're already doing this */
3872 ResponseType r = (ResponseType) add_route_dialog->run ();
3874 add_route_dialog->hide();
3877 case RESPONSE_ACCEPT:
3884 if ((count = add_route_dialog->count()) <= 0) {
3888 setup_order_hint(add_route_dialog->insert_at());
3890 string template_path = add_route_dialog->track_template();
3891 DisplaySuspender ds;
3893 if (!template_path.empty()) {
3894 if (add_route_dialog->name_template_is_default()) {
3895 _session->new_route_from_template (count, template_path, string());
3897 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3902 ChanCount input_chan= add_route_dialog->channels ();
3903 ChanCount output_chan;
3904 string name_template = add_route_dialog->name_template ();
3905 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3906 RouteGroup* route_group = add_route_dialog->route_group ();
3907 AutoConnectOption oac = Config->get_output_auto_connect();
3909 if (oac & AutoConnectMaster) {
3910 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3911 output_chan.set (DataType::MIDI, 0);
3913 output_chan = input_chan;
3916 /* XXX do something with name template */
3918 switch (add_route_dialog->type_wanted()) {
3919 case AddRouteDialog::AudioTrack:
3920 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3922 case AddRouteDialog::MidiTrack:
3923 session_add_midi_track (route_group, count, name_template, instrument);
3925 case AddRouteDialog::MixedTrack:
3926 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3928 case AddRouteDialog::AudioBus:
3929 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3935 ARDOUR_UI::stop_video_server (bool ask_confirm)
3937 if (!video_server_process && ask_confirm) {
3938 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3940 if (video_server_process) {
3942 ArdourDialog confirm (_("Stop Video-Server"), true);
3943 Label m (_("Do you really want to stop the Video Server?"));
3944 confirm.get_vbox()->pack_start (m, true, true);
3945 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3946 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3947 confirm.show_all ();
3948 if (confirm.run() == RESPONSE_CANCEL) {
3952 delete video_server_process;
3953 video_server_process =0;
3958 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3960 ARDOUR_UI::start_video_server( float_window, true);
3964 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3970 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3971 if (video_server_process) {
3972 popup_error(_("The Video Server is already started."));
3974 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3980 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3982 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3984 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3986 video_server_dialog->set_transient_for (*float_window);
3989 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3990 video_server_dialog->hide();
3992 ResponseType r = (ResponseType) video_server_dialog->run ();
3993 video_server_dialog->hide();
3994 if (r != RESPONSE_ACCEPT) { return false; }
3995 if (video_server_dialog->show_again()) {
3996 Config->set_show_video_server_dialog(false);
4000 std::string icsd_exec = video_server_dialog->get_exec_path();
4001 std::string icsd_docroot = video_server_dialog->get_docroot();
4002 if (icsd_docroot.empty()) {
4003 #ifndef PLATFORM_WINDOWS
4004 icsd_docroot = X_("/");
4006 icsd_docroot = X_("C:\\");
4011 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4012 warning << _("Specified docroot is not an existing directory.") << endmsg;
4015 #ifndef PLATFORM_WINDOWS
4016 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4017 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4018 warning << _("Given Video Server is not an executable file.") << endmsg;
4022 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4023 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4024 warning << _("Given Video Server is not an executable file.") << endmsg;
4030 argp=(char**) calloc(9,sizeof(char*));
4031 argp[0] = strdup(icsd_exec.c_str());
4032 argp[1] = strdup("-P");
4033 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4034 argp[3] = strdup("-p");
4035 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4036 argp[5] = strdup("-C");
4037 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4038 argp[7] = strdup(icsd_docroot.c_str());
4040 stop_video_server();
4042 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4043 Config->set_video_advanced_setup(false);
4045 std::ostringstream osstream;
4046 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4047 Config->set_video_server_url(osstream.str());
4048 Config->set_video_server_docroot(icsd_docroot);
4049 Config->set_video_advanced_setup(true);
4052 if (video_server_process) {
4053 delete video_server_process;
4056 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4057 if (video_server_process->start()) {
4058 warning << _("Cannot launch the video-server") << endmsg;
4061 int timeout = 120; // 6 sec
4062 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4063 Glib::usleep (50000);
4065 if (--timeout <= 0 || !video_server_process->is_running()) break;
4068 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4070 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4071 delete video_server_process;
4072 video_server_process = 0;
4080 ARDOUR_UI::add_video (Gtk::Window* float_window)
4086 if (!start_video_server(float_window, false)) {
4087 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4092 add_video_dialog->set_transient_for (*float_window);
4095 if (add_video_dialog->is_visible()) {
4096 /* we're already doing this */
4100 ResponseType r = (ResponseType) add_video_dialog->run ();
4101 add_video_dialog->hide();
4102 if (r != RESPONSE_ACCEPT) { return; }
4104 bool local_file, orig_local_file;
4105 std::string path = add_video_dialog->file_name(local_file);
4107 std::string orig_path = path;
4108 orig_local_file = local_file;
4110 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4112 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4113 warning << string_compose(_("could not open %1"), path) << endmsg;
4116 if (!local_file && path.length() == 0) {
4117 warning << _("no video-file selected") << endmsg;
4121 std::string audio_from_video;
4122 bool detect_ltc = false;
4124 switch (add_video_dialog->import_option()) {
4125 case VTL_IMPORT_TRANSCODE:
4127 TranscodeVideoDialog *transcode_video_dialog;
4128 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4129 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4130 transcode_video_dialog->hide();
4131 if (r != RESPONSE_ACCEPT) {
4132 delete transcode_video_dialog;
4136 audio_from_video = transcode_video_dialog->get_audiofile();
4138 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4141 else if (!audio_from_video.empty()) {
4142 editor->embed_audio_from_video(
4144 video_timeline->get_offset(),
4145 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4148 switch (transcode_video_dialog->import_option()) {
4149 case VTL_IMPORT_TRANSCODED:
4150 path = transcode_video_dialog->get_filename();
4153 case VTL_IMPORT_REFERENCE:
4156 delete transcode_video_dialog;
4159 delete transcode_video_dialog;
4163 case VTL_IMPORT_NONE:
4167 /* strip _session->session_directory().video_path() from video file if possible */
4168 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4169 path=path.substr(_session->session_directory().video_path().size());
4170 if (path.at(0) == G_DIR_SEPARATOR) {
4171 path=path.substr(1);
4175 video_timeline->set_update_session_fps(auto_set_session_fps);
4177 if (video_timeline->video_file_info(path, local_file)) {
4178 XMLNode* node = new XMLNode(X_("Videotimeline"));
4179 node->add_property (X_("Filename"), path);
4180 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4181 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4182 if (orig_local_file) {
4183 node->add_property (X_("OriginalVideoFile"), orig_path);
4185 node->remove_property (X_("OriginalVideoFile"));
4187 _session->add_extra_xml (*node);
4188 _session->set_dirty ();
4190 if (!audio_from_video.empty() && detect_ltc) {
4191 std::vector<LTCFileReader::LTCMap> ltc_seq;
4194 /* TODO ask user about TV standard (LTC alignment if any) */
4195 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4196 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4198 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4200 /* TODO seek near end of file, and read LTC until end.
4201 * if it fails to find any LTC frames, scan complete file
4203 * calculate drift of LTC compared to video-duration,
4204 * ask user for reference (timecode from start/mid/end)
4207 // LTCFileReader will have written error messages
4210 ::g_unlink(audio_from_video.c_str());
4212 if (ltc_seq.size() == 0) {
4213 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4215 /* the very first TC in the file is somteimes not aligned properly */
4216 int i = ltc_seq.size() -1;
4217 ARDOUR::frameoffset_t video_start_offset =
4218 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4219 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4220 video_timeline->set_offset(video_start_offset);
4224 _session->maybe_update_session_range(
4225 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4226 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4229 if (add_video_dialog->launch_xjadeo() && local_file) {
4230 editor->set_xjadeo_sensitive(true);
4231 editor->toggle_xjadeo_proc(1);
4233 editor->toggle_xjadeo_proc(0);
4235 editor->toggle_ruler_video(true);
4240 ARDOUR_UI::remove_video ()
4242 video_timeline->close_session();
4243 editor->toggle_ruler_video(false);
4246 video_timeline->set_offset_locked(false);
4247 video_timeline->set_offset(0);
4249 /* delete session state */
4250 XMLNode* node = new XMLNode(X_("Videotimeline"));
4251 _session->add_extra_xml(*node);
4252 node = new XMLNode(X_("Videomonitor"));
4253 _session->add_extra_xml(*node);
4254 node = new XMLNode(X_("Videoexport"));
4255 _session->add_extra_xml(*node);
4256 stop_video_server();
4260 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4262 if (localcacheonly) {
4263 video_timeline->vmon_update();
4265 video_timeline->flush_cache();
4267 editor->queue_visual_videotimeline_update();
4271 ARDOUR_UI::export_video (bool range)
4273 if (ARDOUR::Config->get_show_video_export_info()) {
4274 ExportVideoInfobox infobox (_session);
4275 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4276 if (infobox.show_again()) {
4277 ARDOUR::Config->set_show_video_export_info(false);
4280 case GTK_RESPONSE_YES:
4281 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4287 export_video_dialog->set_session (_session);
4288 export_video_dialog->apply_state(editor->get_selection().time, range);
4289 export_video_dialog->run ();
4290 export_video_dialog->hide ();
4294 ARDOUR_UI::mixer_settings () const
4299 node = _session->instant_xml(X_("Mixer"));
4301 node = Config->instant_xml(X_("Mixer"));
4305 node = new XMLNode (X_("Mixer"));
4312 ARDOUR_UI::main_window_settings () const
4317 node = _session->instant_xml(X_("Main"));
4319 node = Config->instant_xml(X_("Main"));
4323 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4324 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4329 node = new XMLNode (X_("Main"));
4336 ARDOUR_UI::editor_settings () const
4341 node = _session->instant_xml(X_("Editor"));
4343 node = Config->instant_xml(X_("Editor"));
4347 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4348 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4353 node = new XMLNode (X_("Editor"));
4360 ARDOUR_UI::keyboard_settings () const
4364 node = Config->extra_xml(X_("Keyboard"));
4367 node = new XMLNode (X_("Keyboard"));
4374 ARDOUR_UI::create_xrun_marker (framepos_t where)
4377 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4378 _session->locations()->add (location);
4383 ARDOUR_UI::halt_on_xrun_message ()
4385 cerr << "HALT on xrun\n";
4386 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4391 ARDOUR_UI::xrun_handler (framepos_t where)
4397 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4399 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4400 create_xrun_marker(where);
4403 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4404 halt_on_xrun_message ();
4409 ARDOUR_UI::disk_overrun_handler ()
4411 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4413 if (!have_disk_speed_dialog_displayed) {
4414 have_disk_speed_dialog_displayed = true;
4415 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4416 The disk system on your computer\n\
4417 was not able to keep up with %1.\n\
4419 Specifically, it failed to write data to disk\n\
4420 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4421 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4427 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4428 static MessageDialog *scan_dlg = NULL;
4429 static ProgressBar *scan_pbar = NULL;
4430 static HBox *scan_tbox = NULL;
4431 static Gtk::Button *scan_timeout_button;
4434 ARDOUR_UI::cancel_plugin_scan ()
4436 PluginManager::instance().cancel_plugin_scan();
4440 ARDOUR_UI::cancel_plugin_timeout ()
4442 PluginManager::instance().cancel_plugin_timeout();
4443 scan_timeout_button->set_sensitive (false);
4447 ARDOUR_UI::plugin_scan_timeout (int timeout)
4449 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4453 scan_pbar->set_sensitive (false);
4454 scan_timeout_button->set_sensitive (true);
4455 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4458 scan_pbar->set_sensitive (false);
4459 scan_timeout_button->set_sensitive (false);
4465 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4467 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4471 const bool cancelled = PluginManager::instance().cancelled();
4472 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4473 if (cancelled && scan_dlg->is_mapped()) {
4478 if (cancelled || !can_cancel) {
4483 static Gtk::Button *cancel_button;
4485 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4486 VBox* vbox = scan_dlg->get_vbox();
4487 vbox->set_size_request(400,-1);
4488 scan_dlg->set_title (_("Scanning for plugins"));
4490 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4491 cancel_button->set_name ("EditorGTKButton");
4492 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4493 cancel_button->show();
4495 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4497 scan_tbox = manage( new HBox() );
4499 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4500 scan_timeout_button->set_name ("EditorGTKButton");
4501 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4502 scan_timeout_button->show();
4504 scan_pbar = manage(new ProgressBar());
4505 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4506 scan_pbar->set_text(_("Scan Timeout"));
4509 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4510 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4512 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4515 assert(scan_dlg && scan_tbox && cancel_button);
4517 if (type == X_("closeme")) {
4521 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4524 if (!can_cancel || !cancelled) {
4525 scan_timeout_button->set_sensitive(false);
4527 cancel_button->set_sensitive(can_cancel && !cancelled);
4533 ARDOUR_UI::gui_idle_handler ()
4536 /* due to idle calls, gtk_events_pending() may always return true */
4537 while (gtk_events_pending() && --timeout) {
4538 gtk_main_iteration ();
4543 ARDOUR_UI::disk_underrun_handler ()
4545 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4547 if (!have_disk_speed_dialog_displayed) {
4548 have_disk_speed_dialog_displayed = true;
4549 MessageDialog* msg = new MessageDialog (
4550 _main_window, string_compose (_("The disk system on your computer\n\
4551 was not able to keep up with %1.\n\
4553 Specifically, it failed to read data from disk\n\
4554 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4555 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4561 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4563 have_disk_speed_dialog_displayed = false;
4568 ARDOUR_UI::session_dialog (std::string msg)
4570 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4574 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4581 ARDOUR_UI::pending_state_dialog ()
4583 HBox* hbox = manage (new HBox());
4584 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4585 ArdourDialog dialog (_("Crash Recovery"), true);
4586 Label message (string_compose (_("\
4587 This session appears to have been in the\n\
4588 middle of recording when %1 or\n\
4589 the computer was shutdown.\n\
4591 %1 can recover any captured audio for\n\
4592 you, or it can ignore it. Please decide\n\
4593 what you would like to do.\n"), PROGRAM_NAME));
4594 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4595 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4596 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4597 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4598 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4599 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4600 dialog.set_default_response (RESPONSE_ACCEPT);
4601 dialog.set_position (WIN_POS_CENTER);
4606 switch (dialog.run ()) {
4607 case RESPONSE_ACCEPT:
4615 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4617 HBox* hbox = new HBox();
4618 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4619 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4620 Label message (string_compose (_("\
4621 This session was created with a sample rate of %1 Hz, but\n\
4622 %2 is currently running at %3 Hz. If you load this session,\n\
4623 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4625 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4626 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4627 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4628 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4629 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4630 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4631 dialog.set_default_response (RESPONSE_ACCEPT);
4632 dialog.set_position (WIN_POS_CENTER);
4637 switch (dialog.run()) {
4638 case RESPONSE_ACCEPT:
4648 ARDOUR_UI::use_config ()
4650 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4652 set_transport_controllable_state (*node);
4657 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4659 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4660 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4662 primary_clock->set (pos);
4665 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4666 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4668 secondary_clock->set (pos);
4671 if (big_clock_window) {
4672 big_clock->set (pos);
4674 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4678 ARDOUR_UI::step_edit_status_change (bool yn)
4680 // XXX should really store pre-step edit status of things
4681 // we make insensitive
4684 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4685 rec_button.set_sensitive (false);
4687 rec_button.unset_active_state ();;
4688 rec_button.set_sensitive (true);
4693 ARDOUR_UI::record_state_changed ()
4695 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4697 if (!_session || !big_clock_window) {
4698 /* why bother - the clock isn't visible */
4702 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4703 big_clock->set_active (true);
4705 big_clock->set_active (false);
4710 ARDOUR_UI::first_idle ()
4713 _session->allow_auto_play (true);
4717 editor->first_idle();
4720 Keyboard::set_can_save_keybindings (true);
4725 ARDOUR_UI::store_clock_modes ()
4727 XMLNode* node = new XMLNode(X_("ClockModes"));
4729 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4730 XMLNode* child = new XMLNode (X_("Clock"));
4732 child->add_property (X_("name"), (*x)->name());
4733 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4734 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4736 node->add_child_nocopy (*child);
4739 _session->add_extra_xml (*node);
4740 _session->set_dirty ();
4743 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4744 : Controllable (name), ui (u), type(tp)
4750 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4753 /* do nothing: these are radio-style actions */
4757 const char *action = 0;
4761 action = X_("Roll");
4764 action = X_("Stop");
4767 action = X_("GotoStart");
4770 action = X_("GotoEnd");
4773 action = X_("Loop");
4776 action = X_("PlaySelection");
4779 action = X_("Record");
4789 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4797 ARDOUR_UI::TransportControllable::get_value (void) const
4824 ARDOUR_UI::setup_profile ()
4826 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4827 Profile->set_small_screen ();
4830 if (g_getenv ("TRX")) {
4831 Profile->set_trx ();
4834 if (g_getenv ("MIXBUS")) {
4835 Profile->set_mixbus ();
4840 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4842 MissingFileDialog dialog (s, str, type);
4847 int result = dialog.run ();
4854 return 1; // quit entire session load
4857 result = dialog.get_action ();
4863 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4865 AmbiguousFileDialog dialog (file, hits);
4872 return dialog.get_which ();
4875 /** Allocate our thread-local buffers */
4877 ARDOUR_UI::get_process_buffers ()
4879 _process_thread->get_buffers ();
4882 /** Drop our thread-local buffers */
4884 ARDOUR_UI::drop_process_buffers ()
4886 _process_thread->drop_buffers ();
4890 ARDOUR_UI::feedback_detected ()
4892 _feedback_exists = true;
4896 ARDOUR_UI::successful_graph_sort ()
4898 _feedback_exists = false;
4902 ARDOUR_UI::midi_panic ()
4905 _session->midi_panic();
4910 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4912 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4913 const char* end_big = "</span>";
4914 const char* start_mono = "<tt>";
4915 const char* end_mono = "</tt>";
4917 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4918 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4919 "From now on, use the -2000 version with older versions of %3"),
4920 xml_path, backup_path, PROGRAM_NAME,
4922 start_mono, end_mono), true);
4929 ARDOUR_UI::reset_peak_display ()
4931 if (!_session || !_session->master_out() || !editor_meter) return;
4932 editor_meter->clear_meters();
4933 editor_meter_max_peak = -INFINITY;
4934 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4938 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4940 if (!_session || !_session->master_out()) return;
4941 if (group == _session->master_out()->route_group()) {
4942 reset_peak_display ();
4947 ARDOUR_UI::reset_route_peak_display (Route* route)
4949 if (!_session || !_session->master_out()) return;
4950 if (_session->master_out().get() == route) {
4951 reset_peak_display ();
4956 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4958 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4959 audio_midi_setup->set_position (WIN_POS_CENTER);
4964 response = audio_midi_setup->run();
4966 case Gtk::RESPONSE_OK:
4967 if (!AudioEngine::instance()->running()) {
4981 ARDOUR_UI::transport_numpad_timeout ()
4983 _numpad_locate_happening = false;
4984 if (_numpad_timeout_connection.connected() )
4985 _numpad_timeout_connection.disconnect();
4990 ARDOUR_UI::transport_numpad_decimal ()
4992 _numpad_timeout_connection.disconnect();
4994 if (_numpad_locate_happening) {
4995 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4996 _numpad_locate_happening = false;
4998 _pending_locate_num = 0;
4999 _numpad_locate_happening = true;
5000 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5005 ARDOUR_UI::transport_numpad_event (int num)
5007 if ( _numpad_locate_happening ) {
5008 _pending_locate_num = _pending_locate_num*10 + num;
5011 case 0: toggle_roll(false, false); break;
5012 case 1: transport_rewind(1); break;
5013 case 2: transport_forward(1); break;
5014 case 3: transport_record(true); break;
5015 case 4: toggle_session_auto_loop(); break;
5016 case 5: transport_record(false); toggle_session_auto_loop(); break;
5017 case 6: toggle_punch(); break;
5018 case 7: toggle_click(); break;
5019 case 8: toggle_auto_return(); break;
5020 case 9: toggle_follow_edits(); break;
5026 ARDOUR_UI::set_flat_buttons ()
5028 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5032 ARDOUR_UI::audioengine_became_silent ()
5034 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5036 Gtk::MESSAGE_WARNING,
5040 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5042 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5043 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5044 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5045 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5046 Gtk::HBox pay_button_box;
5047 Gtk::HBox subscribe_button_box;
5049 pay_button_box.pack_start (pay_button, true, false);
5050 subscribe_button_box.pack_start (subscribe_button, true, false);
5052 bool (*openuri)(const char*) = PBD::open_uri; /* this forces selection of the const char* variant of PBD::open_uri(), which we need to avoid ambiguity below */
5054 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5055 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5057 msg.get_vbox()->pack_start (pay_label);
5058 msg.get_vbox()->pack_start (pay_button_box);
5059 msg.get_vbox()->pack_start (subscribe_label);
5060 msg.get_vbox()->pack_start (subscribe_button_box);
5062 msg.get_vbox()->show_all ();
5064 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5065 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5066 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5071 case Gtk::RESPONSE_YES:
5072 AudioEngine::instance()->reset_silence_countdown ();
5075 case Gtk::RESPONSE_NO:
5077 save_state_canfail ("");
5081 case Gtk::RESPONSE_CANCEL:
5083 /* don't reset, save session and exit */
5089 ARDOUR_UI::hide_application ()
5091 Application::instance ()-> hide ();
5095 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5097 /* icons, titles, WM stuff */
5099 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5101 if (window_icons.empty()) {
5102 Glib::RefPtr<Gdk::Pixbuf> icon;
5103 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5104 window_icons.push_back (icon);
5106 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5107 window_icons.push_back (icon);
5109 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5110 window_icons.push_back (icon);
5112 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5113 window_icons.push_back (icon);
5117 if (!window_icons.empty()) {
5118 window.set_default_icon_list (window_icons);
5121 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5123 if (!name.empty()) {
5127 window.set_title (title.get_string());
5128 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5130 window.set_flags (CAN_FOCUS);
5131 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5133 /* This is a hack to ensure that GTK-accelerators continue to
5134 * work. Once we switch over to entirely native bindings, this will be
5135 * unnecessary and should be removed
5137 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5139 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5140 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5141 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5142 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5146 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5148 Gtkmm2ext::Bindings* bindings = 0;
5149 Gtk::Window* window = 0;
5151 /* until we get ardour bindings working, we are not handling key
5155 if (ev->type != GDK_KEY_PRESS) {
5159 if (event_window == &_main_window) {
5161 window = event_window;
5163 /* find current tab contents */
5165 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5167 /* see if it uses the ardour binding system */
5170 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5173 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5177 window = event_window;
5179 /* see if window uses ardour binding system */
5181 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5184 /* An empty binding set is treated as if it doesn't exist */
5186 if (bindings && bindings->empty()) {
5190 return key_press_focus_accelerator_handler (*window, ev, bindings);
5194 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5196 GtkWindow* win = window.gobj();
5197 GtkWidget* focus = gtk_window_get_focus (win);
5198 bool special_handling_of_unmodified_accelerators = false;
5199 /* consider all relevant modifiers but not LOCK or SHIFT */
5200 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5202 GdkModifierType modifier = GdkModifierType (ev->state);
5203 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5207 /* some widget has keyboard focus */
5209 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5211 /* A particular kind of focusable widget currently has keyboard
5212 * focus. All unmodified key events should go to that widget
5213 * first and not be used as an accelerator by default
5216 special_handling_of_unmodified_accelerators = true;
5220 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7\n",
5223 show_gdk_event_state (ev->state),
5224 special_handling_of_unmodified_accelerators,
5225 Keyboard::some_magic_widget_has_focus(),
5227 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5229 /* This exists to allow us to override the way GTK handles
5230 key events. The normal sequence is:
5232 a) event is delivered to a GtkWindow
5233 b) accelerators/mnemonics are activated
5234 c) if (b) didn't handle the event, propagate to
5235 the focus widget and/or focus chain
5237 The problem with this is that if the accelerators include
5238 keys without modifiers, such as the space bar or the
5239 letter "e", then pressing the key while typing into
5240 a text entry widget results in the accelerator being
5241 activated, instead of the desired letter appearing
5244 There is no good way of fixing this, but this
5245 represents a compromise. The idea is that
5246 key events involving modifiers (not Shift)
5247 get routed into the activation pathway first, then
5248 get propagated to the focus widget if necessary.
5250 If the key event doesn't involve modifiers,
5251 we deliver to the focus widget first, thus allowing
5252 it to get "normal text" without interference
5255 Of course, this can also be problematic: if there
5256 is a widget with focus, then it will swallow
5257 all "normal text" accelerators.
5261 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5263 /* no special handling or there are modifiers in effect: accelerate first */
5265 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5266 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5267 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5269 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5270 KeyboardKey k (ev->state, ev->keyval);
5274 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5276 if (bindings->activate (k, Bindings::Press)) {
5277 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5282 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5284 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5285 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5289 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5291 if (gtk_window_propagate_key_event (win, ev)) {
5292 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5298 /* no modifiers, propagate first */
5300 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5302 if (gtk_window_propagate_key_event (win, ev)) {
5303 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5307 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5308 KeyboardKey k (ev->state, ev->keyval);
5312 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5315 if (bindings->activate (k, Bindings::Press)) {
5316 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5322 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5324 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
5325 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5330 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5335 ARDOUR_UI::load_bindings ()
5337 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5338 error << _("Global keybindings are missing") << endmsg;
5343 ARDOUR_UI::cancel_solo ()
5346 if (_session->soloing()) {
5347 _session->set_solo (_session->get_routes(), false);
5348 } else if (_session->listening()) {
5349 _session->set_listen (_session->get_routes(), false);
5352 _session->clear_all_solo_state (_session->get_routes()); // safeguard, ideally this won't do anything, check the log-window