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)
296 , editor_visibility_button (S_("Window|Editor"))
297 , mixer_visibility_button (S_("Window|Mixer"))
298 , prefs_visibility_button (S_("Window|Preferences"))
300 Gtkmm2ext::init (localedir);
302 UIConfiguration::instance().post_gui_init ();
304 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
305 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
307 /* configuration was modified, exit immediately */
311 if (theArdourUI == 0) {
315 /* stop libxml from spewing to stdout/stderr */
317 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
318 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
320 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
321 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
322 UIConfiguration::instance().map_parameters (pc);
324 roll_button.set_controllable (roll_controllable);
325 stop_button.set_controllable (stop_controllable);
326 goto_start_button.set_controllable (goto_start_controllable);
327 goto_end_button.set_controllable (goto_end_controllable);
328 auto_loop_button.set_controllable (auto_loop_controllable);
329 play_selection_button.set_controllable (play_selection_controllable);
330 rec_button.set_controllable (rec_controllable);
332 roll_button.set_name ("transport button");
333 stop_button.set_name ("transport button");
334 goto_start_button.set_name ("transport button");
335 goto_end_button.set_name ("transport button");
336 auto_loop_button.set_name ("transport button");
337 play_selection_button.set_name ("transport button");
338 rec_button.set_name ("transport recenable button");
339 midi_panic_button.set_name ("transport button");
341 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
342 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
344 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
346 /* handle dialog requests */
348 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
350 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
352 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
354 /* handle Audio/MIDI setup when session requires it */
356 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
358 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
360 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
362 /* handle requests to quit (coming from JACK session) */
364 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
366 /* tell the user about feedback */
368 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
369 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
371 /* handle requests to deal with missing files */
373 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
375 /* and ambiguous files */
377 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
379 /* also plugin scan messages */
380 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
381 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
383 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
385 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
388 /* lets get this party started */
390 setup_gtk_ardour_enums ();
393 SessionEvent::create_per_thread_pool ("GUI", 4096);
395 /* we like keyboards */
397 keyboard = new ArdourKeyboard(*this);
399 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
401 keyboard->set_state (*node, Stateful::loading_state_version);
404 UIConfiguration::instance().reset_dpi ();
406 TimeAxisViewItem::set_constant_heights ();
408 /* Set this up so that our window proxies can register actions */
410 ActionManager::init ();
412 /* The following must happen after ARDOUR::init() so that Config is set up */
414 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
417 key_editor.set_state (*ui_xml, 0);
418 session_option_editor.set_state (*ui_xml, 0);
419 speaker_config_window.set_state (*ui_xml, 0);
420 about.set_state (*ui_xml, 0);
421 add_route_dialog.set_state (*ui_xml, 0);
422 add_video_dialog.set_state (*ui_xml, 0);
423 route_params.set_state (*ui_xml, 0);
424 bundle_manager.set_state (*ui_xml, 0);
425 location_ui.set_state (*ui_xml, 0);
426 big_clock_window.set_state (*ui_xml, 0);
427 audio_port_matrix.set_state (*ui_xml, 0);
428 midi_port_matrix.set_state (*ui_xml, 0);
429 export_video_dialog.set_state (*ui_xml, 0);
432 /* Separate windows */
434 WM::Manager::instance().register_window (&key_editor);
435 WM::Manager::instance().register_window (&session_option_editor);
436 WM::Manager::instance().register_window (&speaker_config_window);
437 WM::Manager::instance().register_window (&about);
438 WM::Manager::instance().register_window (&add_route_dialog);
439 WM::Manager::instance().register_window (&add_video_dialog);
440 WM::Manager::instance().register_window (&route_params);
441 WM::Manager::instance().register_window (&audio_midi_setup);
442 WM::Manager::instance().register_window (&export_video_dialog);
443 WM::Manager::instance().register_window (&bundle_manager);
444 WM::Manager::instance().register_window (&location_ui);
445 WM::Manager::instance().register_window (&big_clock_window);
446 WM::Manager::instance().register_window (&audio_port_matrix);
447 WM::Manager::instance().register_window (&midi_port_matrix);
449 /* Trigger setting up the color scheme and loading the GTK RC file */
451 UIConfiguration::instance().load_rc_file (false);
453 _process_thread = new ProcessThread ();
454 _process_thread->init ();
456 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
461 GlobalPortMatrixWindow*
462 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
467 return new GlobalPortMatrixWindow (_session, type);
471 ARDOUR_UI::attach_to_engine ()
473 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
474 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
478 ARDOUR_UI::engine_stopped ()
480 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
481 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
482 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
483 update_sample_rate (0);
488 ARDOUR_UI::engine_running ()
490 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
491 if (first_time_engine_run) {
493 first_time_engine_run = false;
497 _session->reset_xrun_count ();
499 update_disk_space ();
501 update_xrun_count ();
502 update_sample_rate (AudioEngine::instance()->sample_rate());
503 update_timecode_format ();
504 update_peak_thread_work ();
505 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
506 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
510 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
512 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
513 /* we can't rely on the original string continuing to exist when we are called
514 again in the GUI thread, so make a copy and note that we need to
517 char *copy = strdup (reason);
518 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
522 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
523 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
525 update_sample_rate (0);
529 /* if the reason is a non-empty string, it means that the backend was shutdown
530 rather than just Ardour.
533 if (strlen (reason)) {
534 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
536 msgstr = string_compose (_("\
537 The audio backend has either been shutdown or it\n\
538 disconnected %1 because %1\n\
539 was not fast enough. Try to restart\n\
540 the audio backend and save the session."), PROGRAM_NAME);
543 MessageDialog msg (_main_window, msgstr);
544 pop_back_splash (msg);
548 free (const_cast<char*> (reason));
553 ARDOUR_UI::post_engine ()
555 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
557 #ifdef AUDIOUNIT_SUPPORT
559 if (AUPluginInfo::au_get_crashlog(au_msg)) {
560 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
561 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
562 info << au_msg << endmsg;
566 ARDOUR::init_post_engine ();
568 /* connect to important signals */
570 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
571 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
572 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
573 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
574 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
576 if (setup_windows ()) {
577 throw failed_constructor ();
580 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
581 XMLNode* n = Config->extra_xml (X_("UI"));
583 _status_bar_visibility.set_state (*n);
586 check_memory_locking();
588 /* this is the first point at which all the possible actions are
589 * available, because some of the available actions are dependent on
590 * aspects of the engine/backend.
593 if (ARDOUR_COMMAND_LINE::show_key_actions) {
596 vector<string> paths;
597 vector<string> labels;
598 vector<string> tooltips;
600 vector<Glib::RefPtr<Gtk::Action> > actions;
602 Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
604 vector<string>::iterator k;
605 vector<string>::iterator p;
607 for (p = paths.begin(), k = keys.begin(); p != paths.end(); ++k, ++p) {
612 cout << *p << " => " << *k << endl;
616 halt_connection.disconnect ();
617 AudioEngine::instance()->stop ();
621 /* this being a GUI and all, we want peakfiles */
623 AudioFileSource::set_build_peakfiles (true);
624 AudioFileSource::set_build_missing_peakfiles (true);
626 /* set default clock modes */
628 primary_clock->set_mode (AudioClock::Timecode);
629 secondary_clock->set_mode (AudioClock::BBT);
631 /* start the time-of-day-clock */
634 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
635 update_wall_clock ();
636 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
641 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
642 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
643 Config->map_parameters (pc);
645 UIConfiguration::instance().map_parameters (pc);
649 ARDOUR_UI::~ARDOUR_UI ()
651 UIConfiguration::instance().save_state();
655 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
656 // don't bother at 'real' exit. the OS cleans up for us.
658 delete primary_clock;
659 delete secondary_clock;
660 delete _process_thread;
665 delete gui_object_state;
666 FastMeter::flush_pattern_cache ();
667 PixFader::flush_pattern_cache ();
671 /* Small trick to flush main-thread event pool.
672 * Other thread-pools are destroyed at pthread_exit(),
673 * but tmain thread termination is too late to trigger Pool::~Pool()
675 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.
676 delete ev->event_pool();
681 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
683 if (Splash::instance()) {
684 Splash::instance()->pop_back_for (win);
689 ARDOUR_UI::configure_timeout ()
691 if (last_configure_time == 0) {
692 /* no configure events yet */
696 /* force a gap of 0.5 seconds since the last configure event
699 if (get_microseconds() - last_configure_time < 500000) {
702 have_configure_timeout = false;
703 save_ardour_state ();
709 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
711 if (have_configure_timeout) {
712 last_configure_time = get_microseconds();
714 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
715 have_configure_timeout = true;
722 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
724 const XMLProperty* prop;
726 if ((prop = node.property ("roll")) != 0) {
727 roll_controllable->set_id (prop->value());
729 if ((prop = node.property ("stop")) != 0) {
730 stop_controllable->set_id (prop->value());
732 if ((prop = node.property ("goto-start")) != 0) {
733 goto_start_controllable->set_id (prop->value());
735 if ((prop = node.property ("goto-end")) != 0) {
736 goto_end_controllable->set_id (prop->value());
738 if ((prop = node.property ("auto-loop")) != 0) {
739 auto_loop_controllable->set_id (prop->value());
741 if ((prop = node.property ("play-selection")) != 0) {
742 play_selection_controllable->set_id (prop->value());
744 if ((prop = node.property ("rec")) != 0) {
745 rec_controllable->set_id (prop->value());
747 if ((prop = node.property ("shuttle")) != 0) {
748 shuttle_box->controllable()->set_id (prop->value());
753 ARDOUR_UI::get_transport_controllable_state ()
755 XMLNode* node = new XMLNode(X_("TransportControllables"));
758 roll_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("roll"), buf);
760 stop_controllable->id().print (buf, sizeof (buf));
761 node->add_property (X_("stop"), buf);
762 goto_start_controllable->id().print (buf, sizeof (buf));
763 node->add_property (X_("goto_start"), buf);
764 goto_end_controllable->id().print (buf, sizeof (buf));
765 node->add_property (X_("goto_end"), buf);
766 auto_loop_controllable->id().print (buf, sizeof (buf));
767 node->add_property (X_("auto_loop"), buf);
768 play_selection_controllable->id().print (buf, sizeof (buf));
769 node->add_property (X_("play_selection"), buf);
770 rec_controllable->id().print (buf, sizeof (buf));
771 node->add_property (X_("rec"), buf);
772 shuttle_box->controllable()->id().print (buf, sizeof (buf));
773 node->add_property (X_("shuttle"), buf);
779 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
782 _session->save_state (snapshot_name);
787 ARDOUR_UI::autosave_session ()
789 if (g_main_depth() > 1) {
790 /* inside a recursive main loop,
791 give up because we may not be able to
797 if (!Config->get_periodic_safety_backups()) {
802 _session->maybe_write_autosave();
809 ARDOUR_UI::session_dirty_changed ()
816 ARDOUR_UI::update_autosave ()
818 if (_session && _session->dirty()) {
819 if (_autosave_connection.connected()) {
820 _autosave_connection.disconnect();
823 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
824 Config->get_periodic_safety_backup_interval() * 1000);
827 if (_autosave_connection.connected()) {
828 _autosave_connection.disconnect();
834 ARDOUR_UI::check_announcements ()
837 string _annc_filename;
840 _annc_filename = PROGRAM_NAME "_announcements_osx_";
841 #elif defined PLATFORM_WINDOWS
842 _annc_filename = PROGRAM_NAME "_announcements_windows_";
844 _annc_filename = PROGRAM_NAME "_announcements_linux_";
846 _annc_filename.append (VERSIONSTRING);
848 _announce_string = "";
850 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
851 FILE* fin = g_fopen (path.c_str(), "rb");
853 while (!feof (fin)) {
856 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
859 _announce_string.append (tmp, len);
864 pingback (VERSIONSTRING, path);
869 _hide_splash (gpointer arg)
871 ((ARDOUR_UI*)arg)->hide_splash();
876 ARDOUR_UI::starting ()
878 Application* app = Application::instance ();
880 bool brand_new_user = ArdourStartup::required ();
882 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
883 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
885 if (ARDOUR_COMMAND_LINE::check_announcements) {
886 check_announcements ();
891 /* we need to create this early because it may need to set the
892 * audio backend end up.
896 audio_midi_setup.get (true);
898 std::cerr << "audio-midi engine setup failed."<< std::endl;
902 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
903 nsm = new NSM_Client;
904 if (!nsm->init (nsm_url)) {
905 /* the ardour executable may have different names:
907 * waf's obj.target for distro versions: eg ardour4, ardourvst4
908 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
909 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
911 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
913 const char *process_name = g_getenv ("ARDOUR_SELF");
914 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
917 // wait for announce reply from nsm server
918 for ( i = 0; i < 5000; ++i) {
922 if (nsm->is_active()) {
927 error << _("NSM server did not announce itself") << endmsg;
930 // wait for open command from nsm server
931 for ( i = 0; i < 5000; ++i) {
934 if (nsm->client_id ()) {
940 error << _("NSM: no client ID provided") << endmsg;
944 if (_session && nsm) {
945 _session->set_nsm_state( nsm->is_active() );
947 error << _("NSM: no session created") << endmsg;
951 // nsm requires these actions disabled
952 vector<string> action_names;
953 action_names.push_back("SaveAs");
954 action_names.push_back("Rename");
955 action_names.push_back("New");
956 action_names.push_back("Open");
957 action_names.push_back("Recent");
958 action_names.push_back("Close");
960 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
961 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
963 act->set_sensitive (false);
970 error << _("NSM: initialization failed") << endmsg;
976 if (brand_new_user) {
977 _initial_verbose_plugin_scan = true;
982 _initial_verbose_plugin_scan = false;
983 switch (s.response ()) {
984 case Gtk::RESPONSE_OK:
991 #ifdef NO_PLUGIN_STATE
993 ARDOUR::RecentSessions rs;
994 ARDOUR::read_recent_sessions (rs);
996 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
998 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1000 /* already used Ardour, have sessions ... warn about plugin state */
1002 ArdourDialog d (_("Free/Demo Version Warning"), true);
1004 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1005 CheckButton c (_("Don't warn me about this again"));
1007 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"),
1008 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1009 _("It will not restore OR save any plugin settings"),
1010 _("If you load an existing session with plugin settings\n"
1011 "they will not be used and will be lost."),
1012 _("To get full access to updates without this limitation\n"
1013 "consider becoming a subscriber for a low cost every month.")));
1014 l.set_justify (JUSTIFY_CENTER);
1016 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1018 d.get_vbox()->pack_start (l, true, true);
1019 d.get_vbox()->pack_start (b, false, false, 12);
1020 d.get_vbox()->pack_start (c, false, false, 12);
1022 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1023 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1027 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1029 if (d.run () != RESPONSE_OK) {
1035 /* go get a session */
1037 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1039 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1040 std::cerr << "Cannot get session parameters."<< std::endl;
1047 WM::Manager::instance().show_visible ();
1049 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1050 * editor window, and we may want stuff to be hidden.
1052 _status_bar_visibility.update ();
1054 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1056 if (splash && splash->is_visible()) {
1057 // in 1 second, hide the splash screen
1058 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1061 /* all other dialogs are created conditionally */
1067 ARDOUR_UI::check_memory_locking ()
1069 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1070 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1074 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1076 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1078 struct rlimit limits;
1080 long pages, page_size;
1082 size_t pages_len=sizeof(pages);
1083 if ((page_size = getpagesize()) < 0 ||
1084 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1086 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1091 ram = (int64_t) pages * (int64_t) page_size;
1094 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1098 if (limits.rlim_cur != RLIM_INFINITY) {
1100 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1104 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1105 "This might cause %1 to run out of memory before your system "
1106 "runs out of memory. \n\n"
1107 "You can view the memory limit with 'ulimit -l', "
1108 "and it is normally controlled by %2"),
1111 X_("/etc/login.conf")
1113 X_(" /etc/security/limits.conf")
1117 msg.set_default_response (RESPONSE_OK);
1119 VBox* vbox = msg.get_vbox();
1121 CheckButton cb (_("Do not show this window again"));
1122 hbox.pack_start (cb, true, false);
1123 vbox->pack_start (hbox);
1128 pop_back_splash (msg);
1132 if (cb.get_active()) {
1133 XMLNode node (X_("no-memory-warning"));
1134 Config->add_instant_xml (node);
1139 #endif // !__APPLE__
1144 ARDOUR_UI::queue_finish ()
1146 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1150 ARDOUR_UI::idle_finish ()
1153 return false; /* do not call again */
1160 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1162 if (_session->dirty()) {
1163 vector<string> actions;
1164 actions.push_back (_("Don't quit"));
1165 actions.push_back (_("Just quit"));
1166 actions.push_back (_("Save and quit"));
1167 switch (ask_about_saving_session(actions)) {
1172 /* use the default name */
1173 if (save_state_canfail ("")) {
1174 /* failed - don't quit */
1175 MessageDialog msg (_main_window,
1176 string_compose (_("\
1177 %1 was unable to save your session.\n\n\
1178 If you still wish to quit, please use the\n\n\
1179 \"Just quit\" option."), PROGRAM_NAME));
1180 pop_back_splash(msg);
1190 second_connection.disconnect ();
1191 point_one_second_connection.disconnect ();
1192 point_zero_something_second_connection.disconnect();
1193 fps_connection.disconnect();
1196 delete ARDOUR_UI::instance()->video_timeline;
1197 ARDOUR_UI::instance()->video_timeline = NULL;
1198 stop_video_server();
1200 /* Save state before deleting the session, as that causes some
1201 windows to be destroyed before their visible state can be
1204 save_ardour_state ();
1206 close_all_dialogs ();
1209 _session->set_clean ();
1210 _session->remove_pending_capture_state ();
1215 halt_connection.disconnect ();
1216 AudioEngine::instance()->stop ();
1217 #ifdef WINDOWS_VST_SUPPORT
1218 fst_stop_threading();
1224 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1226 ArdourDialog window (_("Unsaved Session"));
1227 Gtk::HBox dhbox; // the hbox for the image and text
1228 Gtk::Label prompt_label;
1229 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1233 assert (actions.size() >= 3);
1235 window.add_button (actions[0], RESPONSE_REJECT);
1236 window.add_button (actions[1], RESPONSE_APPLY);
1237 window.add_button (actions[2], RESPONSE_ACCEPT);
1239 window.set_default_response (RESPONSE_ACCEPT);
1241 Gtk::Button noquit_button (msg);
1242 noquit_button.set_name ("EditorGTKButton");
1246 if (_session->snap_name() == _session->name()) {
1247 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?"),
1248 _session->snap_name());
1250 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?"),
1251 _session->snap_name());
1254 prompt_label.set_text (prompt);
1255 prompt_label.set_name (X_("PrompterLabel"));
1256 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1258 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1259 dhbox.set_homogeneous (false);
1260 dhbox.pack_start (*dimage, false, false, 5);
1261 dhbox.pack_start (prompt_label, true, false, 5);
1262 window.get_vbox()->pack_start (dhbox);
1264 window.set_name (_("Prompter"));
1265 window.set_modal (true);
1266 window.set_resizable (false);
1269 prompt_label.show();
1274 ResponseType r = (ResponseType) window.run();
1279 case RESPONSE_ACCEPT: // save and get out of here
1281 case RESPONSE_APPLY: // get out of here
1292 ARDOUR_UI::every_second ()
1295 update_xrun_count ();
1296 update_buffer_load ();
1297 update_disk_space ();
1298 update_timecode_format ();
1299 update_peak_thread_work ();
1301 if (nsm && nsm->is_active ()) {
1304 if (!_was_dirty && _session->dirty ()) {
1308 else if (_was_dirty && !_session->dirty ()){
1316 ARDOUR_UI::every_point_one_seconds ()
1318 // TODO get rid of this..
1319 // ShuttleControl is updated directly via TransportStateChange signal
1323 ARDOUR_UI::every_point_zero_something_seconds ()
1325 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1327 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1328 float mpeak = editor_meter->update_meters();
1329 if (mpeak > editor_meter_max_peak) {
1330 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1331 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1338 ARDOUR_UI::set_fps_timeout_connection ()
1340 unsigned int interval = 40;
1341 if (!_session) return;
1342 if (_session->timecode_frames_per_second() != 0) {
1343 /* ideally we'll use a select() to sleep and not accumulate
1344 * idle time to provide a regular periodic signal.
1345 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1346 * However, that'll require a dedicated thread and cross-thread
1347 * signals to the GUI Thread..
1349 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1350 * _session->frame_rate() / _session->nominal_frame_rate()
1351 / _session->timecode_frames_per_second()
1353 #ifdef PLATFORM_WINDOWS
1354 // the smallest windows scheduler time-slice is ~15ms.
1355 // periodic GUI timeouts shorter than that will cause
1356 // WaitForSingleObject to spinlock (100% of one CPU Core)
1357 // and gtk never enters idle mode.
1358 // also changing timeBeginPeriod(1) does not affect that in
1359 // any beneficial way, so we just limit the max rate for now.
1360 interval = std::max(30u, interval); // at most ~33Hz.
1362 interval = std::max(8u, interval); // at most 120Hz.
1365 fps_connection.disconnect();
1366 Timers::set_fps_interval (interval);
1370 ARDOUR_UI::update_sample_rate (framecnt_t)
1374 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1376 if (!AudioEngine::instance()->connected()) {
1378 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1382 framecnt_t rate = AudioEngine::instance()->sample_rate();
1385 /* no sample rate available */
1386 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1389 if (fmod (rate, 1000.0) != 0.0) {
1390 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1391 (float) rate / 1000.0f,
1392 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1394 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1396 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1400 sample_rate_label.set_markup (buf);
1404 ARDOUR_UI::update_format ()
1407 format_label.set_text ("");
1412 s << _("File:") << X_(" <span foreground=\"green\">");
1414 switch (_session->config.get_native_file_header_format ()) {
1446 switch (_session->config.get_native_file_data_format ()) {
1460 format_label.set_markup (s.str ());
1464 ARDOUR_UI::update_xrun_count ()
1468 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1469 should also be changed.
1473 const unsigned int x = _session->get_xrun_count ();
1475 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1477 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1480 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1482 xrun_label.set_markup (buf);
1483 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1487 ARDOUR_UI::update_cpu_load ()
1491 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1492 should also be changed.
1495 double const c = AudioEngine::instance()->get_dsp_load ();
1496 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1497 cpu_load_label.set_markup (buf);
1501 ARDOUR_UI::update_peak_thread_work ()
1504 const int c = SourceFactory::peak_work_queue_length ();
1506 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1507 peak_thread_work_label.set_markup (buf);
1509 peak_thread_work_label.set_markup (X_(""));
1514 ARDOUR_UI::update_buffer_load ()
1518 uint32_t const playback = _session ? _session->playback_load () : 100;
1519 uint32_t const capture = _session ? _session->capture_load () : 100;
1521 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1522 should also be changed.
1528 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1529 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1530 playback <= 5 ? X_("red") : X_("green"),
1532 capture <= 5 ? X_("red") : X_("green"),
1536 buffer_load_label.set_markup (buf);
1538 buffer_load_label.set_text ("");
1543 ARDOUR_UI::count_recenabled_streams (Route& route)
1545 Track* track = dynamic_cast<Track*>(&route);
1546 if (track && track->record_enabled()) {
1547 rec_enabled_streams += track->n_inputs().n_total();
1552 ARDOUR_UI::update_disk_space()
1554 if (_session == 0) {
1558 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1560 framecnt_t fr = _session->frame_rate();
1563 /* skip update - no SR available */
1568 /* Available space is unknown */
1569 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1570 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1571 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1573 rec_enabled_streams = 0;
1574 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1576 framecnt_t frames = opt_frames.get_value_or (0);
1578 if (rec_enabled_streams) {
1579 frames /= rec_enabled_streams;
1586 hrs = frames / (fr * 3600);
1589 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1591 frames -= hrs * fr * 3600;
1592 mins = frames / (fr * 60);
1593 frames -= mins * fr * 60;
1596 bool const low = (hrs == 0 && mins <= 30);
1600 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1601 low ? X_("red") : X_("green"),
1607 disk_space_label.set_markup (buf);
1611 ARDOUR_UI::update_timecode_format ()
1617 TimecodeSlave* tcslave;
1618 SyncSource sync_src = Config->get_sync_source();
1620 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1621 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1626 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1627 matching ? X_("green") : X_("red"),
1628 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1630 snprintf (buf, sizeof (buf), "TC: n/a");
1633 timecode_format_label.set_markup (buf);
1637 ARDOUR_UI::update_wall_clock ()
1641 static int last_min = -1;
1644 tm_now = localtime (&now);
1645 if (last_min != tm_now->tm_min) {
1647 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1648 wall_clock_label.set_text (buf);
1649 last_min = tm_now->tm_min;
1656 ARDOUR_UI::open_recent_session ()
1658 bool can_return = (_session != 0);
1660 SessionDialog recent_session_dialog;
1664 ResponseType r = (ResponseType) recent_session_dialog.run ();
1667 case RESPONSE_ACCEPT:
1671 recent_session_dialog.hide();
1678 recent_session_dialog.hide();
1682 std::string path = recent_session_dialog.session_folder();
1683 std::string state = recent_session_dialog.session_name (should_be_new);
1685 if (should_be_new == true) {
1689 _session_is_new = false;
1691 if (load_session (path, state) == 0) {
1700 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1702 if (!AudioEngine::instance()->connected()) {
1703 MessageDialog msg (parent, string_compose (
1704 _("%1 is not connected to any audio backend.\n"
1705 "You cannot open or close sessions in this condition"),
1707 pop_back_splash (msg);
1715 ARDOUR_UI::open_session ()
1717 if (!check_audioengine (_main_window)) {
1721 /* ardour sessions are folders */
1722 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1723 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1724 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1725 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1728 string session_parent_dir = Glib::path_get_dirname(_session->path());
1729 open_session_selector.set_current_folder(session_parent_dir);
1731 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1734 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1736 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1737 string default_session_folder = Config->get_default_session_parent_dir();
1738 open_session_selector.add_shortcut_folder (default_session_folder);
1740 catch (Glib::Error & e) {
1741 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1744 FileFilter session_filter;
1745 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1746 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1747 open_session_selector.add_filter (session_filter);
1748 open_session_selector.set_filter (session_filter);
1750 int response = open_session_selector.run();
1751 open_session_selector.hide ();
1753 if (response == Gtk::RESPONSE_CANCEL) {
1757 string session_path = open_session_selector.get_filename();
1761 if (session_path.length() > 0) {
1762 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1763 _session_is_new = isnew;
1764 load_session (path, name);
1771 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1772 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1774 list<boost::shared_ptr<MidiTrack> > tracks;
1776 if (_session == 0) {
1777 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1782 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1784 if (tracks.size() != how_many) {
1785 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1790 MessageDialog msg (_main_window,
1791 string_compose (_("There are insufficient ports available\n\
1792 to create a new track or bus.\n\
1793 You should save %1, exit and\n\
1794 restart with more ports."), PROGRAM_NAME));
1801 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1803 ChanCount one_midi_channel;
1804 one_midi_channel.set (DataType::MIDI, 1);
1807 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1812 ARDOUR_UI::session_add_audio_route (
1814 int32_t input_channels,
1815 int32_t output_channels,
1816 ARDOUR::TrackMode mode,
1817 RouteGroup* route_group,
1819 string const & name_template
1822 list<boost::shared_ptr<AudioTrack> > tracks;
1825 if (_session == 0) {
1826 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1832 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1834 if (tracks.size() != how_many) {
1835 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1841 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1843 if (routes.size() != how_many) {
1844 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1851 MessageDialog msg (_main_window,
1852 string_compose (_("There are insufficient ports available\n\
1853 to create a new track or bus.\n\
1854 You should save %1, exit and\n\
1855 restart with more ports."), PROGRAM_NAME));
1856 pop_back_splash (msg);
1862 ARDOUR_UI::transport_goto_start ()
1865 _session->goto_start();
1867 /* force displayed area in editor to start no matter
1868 what "follow playhead" setting is.
1872 editor->center_screen (_session->current_start_frame ());
1878 ARDOUR_UI::transport_goto_zero ()
1881 _session->request_locate (0);
1883 /* force displayed area in editor to start no matter
1884 what "follow playhead" setting is.
1888 editor->reset_x_origin (0);
1894 ARDOUR_UI::transport_goto_wallclock ()
1896 if (_session && editor) {
1903 localtime_r (&now, &tmnow);
1905 framecnt_t frame_rate = _session->frame_rate();
1907 if (frame_rate == 0) {
1908 /* no frame rate available */
1912 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1913 frames += tmnow.tm_min * (60 * frame_rate);
1914 frames += tmnow.tm_sec * frame_rate;
1916 _session->request_locate (frames, _session->transport_rolling ());
1918 /* force displayed area in editor to start no matter
1919 what "follow playhead" setting is.
1923 editor->center_screen (frames);
1929 ARDOUR_UI::transport_goto_end ()
1932 framepos_t const frame = _session->current_end_frame();
1933 _session->request_locate (frame);
1935 /* force displayed area in editor to start no matter
1936 what "follow playhead" setting is.
1940 editor->center_screen (frame);
1946 ARDOUR_UI::transport_stop ()
1952 if (_session->is_auditioning()) {
1953 _session->cancel_audition ();
1957 _session->request_stop (false, true);
1960 /** Check if any tracks are record enabled. If none are, record enable all of them.
1961 * @return true if track record-enabled status was changed, false otherwise.
1964 ARDOUR_UI::trx_record_enable_all_tracks ()
1970 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1971 bool none_record_enabled = true;
1973 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1974 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1977 if (t->record_enabled()) {
1978 none_record_enabled = false;
1983 if (none_record_enabled) {
1984 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1987 return none_record_enabled;
1991 ARDOUR_UI::transport_record (bool roll)
1994 switch (_session->record_status()) {
1995 case Session::Disabled:
1996 if (_session->ntracks() == 0) {
1997 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."));
2001 if (Profile->get_trx()) {
2002 roll = trx_record_enable_all_tracks ();
2004 _session->maybe_enable_record ();
2009 case Session::Recording:
2011 _session->request_stop();
2013 _session->disable_record (false, true);
2017 case Session::Enabled:
2018 _session->disable_record (false, true);
2024 ARDOUR_UI::transport_roll ()
2030 if (_session->is_auditioning()) {
2035 if (_session->config.get_external_sync()) {
2036 switch (Config->get_sync_source()) {
2040 /* transport controlled by the master */
2046 bool rolling = _session->transport_rolling();
2048 if (_session->get_play_loop()) {
2050 /* If loop playback is not a mode, then we should cancel
2051 it when this action is requested. If it is a mode
2052 we just leave it in place.
2055 if (!Config->get_loop_is_mode()) {
2056 /* XXX it is not possible to just leave seamless loop and keep
2057 playing at present (nov 4th 2009)
2059 if (!Config->get_seamless_loop()) {
2060 /* stop loop playback and stop rolling */
2061 _session->request_play_loop (false, true);
2062 } else if (rolling) {
2063 /* stop loop playback but keep rolling */
2064 _session->request_play_loop (false, false);
2068 } else if (_session->get_play_range () ) {
2069 /* stop playing a range if we currently are */
2070 _session->request_play_range (0, true);
2074 _session->request_transport_speed (1.0f);
2079 ARDOUR_UI::get_smart_mode() const
2081 return ( editor->get_smart_mode() );
2086 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2092 if (_session->is_auditioning()) {
2093 _session->cancel_audition ();
2097 if (_session->config.get_external_sync()) {
2098 switch (Config->get_sync_source()) {
2102 /* transport controlled by the master */
2107 bool rolling = _session->transport_rolling();
2108 bool affect_transport = true;
2110 if (rolling && roll_out_of_bounded_mode) {
2111 /* drop out of loop/range playback but leave transport rolling */
2112 if (_session->get_play_loop()) {
2113 if (_session->actively_recording()) {
2115 /* just stop using the loop, then actually stop
2118 _session->request_play_loop (false, affect_transport);
2121 if (Config->get_seamless_loop()) {
2122 /* the disk buffers contain copies of the loop - we can't
2123 just keep playing, so stop the transport. the user
2124 can restart as they wish.
2126 affect_transport = true;
2128 /* disk buffers are normal, so we can keep playing */
2129 affect_transport = false;
2131 _session->request_play_loop (false, affect_transport);
2133 } else if (_session->get_play_range ()) {
2134 affect_transport = false;
2135 _session->request_play_range (0, true);
2139 if (affect_transport) {
2141 _session->request_stop (with_abort, true);
2143 /* the only external sync condition we can be in here
2144 * would be Engine (JACK) sync, in which case we still
2148 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
2149 _session->request_play_range (&editor->get_selection().time, true);
2150 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2152 _session->request_transport_speed (1.0f);
2158 ARDOUR_UI::toggle_session_auto_loop ()
2164 Location * looploc = _session->locations()->auto_loop_location();
2170 if (_session->get_play_loop()) {
2172 /* looping enabled, our job is to disable it */
2174 _session->request_play_loop (false);
2178 /* looping not enabled, our job is to enable it.
2180 loop-is-NOT-mode: this action always starts the transport rolling.
2181 loop-IS-mode: this action simply sets the loop play mechanism, but
2182 does not start transport.
2184 if (Config->get_loop_is_mode()) {
2185 _session->request_play_loop (true, false);
2187 _session->request_play_loop (true, true);
2191 //show the loop markers
2192 looploc->set_hidden (false, this);
2196 ARDOUR_UI::transport_play_selection ()
2202 editor->play_selection ();
2206 ARDOUR_UI::transport_play_preroll ()
2211 editor->play_with_preroll ();
2215 ARDOUR_UI::transport_rewind (int option)
2217 float current_transport_speed;
2220 current_transport_speed = _session->transport_speed();
2222 if (current_transport_speed >= 0.0f) {
2225 _session->request_transport_speed (-1.0f);
2228 _session->request_transport_speed (-4.0f);
2231 _session->request_transport_speed (-0.5f);
2236 _session->request_transport_speed (current_transport_speed * 1.5f);
2242 ARDOUR_UI::transport_forward (int option)
2248 float current_transport_speed = _session->transport_speed();
2250 if (current_transport_speed <= 0.0f) {
2253 _session->request_transport_speed (1.0f);
2256 _session->request_transport_speed (4.0f);
2259 _session->request_transport_speed (0.5f);
2264 _session->request_transport_speed (current_transport_speed * 1.5f);
2269 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2275 boost::shared_ptr<Route> r;
2277 if ((r = _session->route_by_remote_id (rid)) != 0) {
2279 boost::shared_ptr<Track> t;
2281 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2282 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2288 ARDOUR_UI::map_transport_state ()
2291 auto_loop_button.unset_active_state ();
2292 play_selection_button.unset_active_state ();
2293 roll_button.unset_active_state ();
2294 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2298 shuttle_box->map_transport_state ();
2300 float sp = _session->transport_speed();
2306 if (_session->get_play_range()) {
2308 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2309 roll_button.unset_active_state ();
2310 auto_loop_button.unset_active_state ();
2312 } else if (_session->get_play_loop ()) {
2314 auto_loop_button.set_active (true);
2315 play_selection_button.set_active (false);
2316 if (Config->get_loop_is_mode()) {
2317 roll_button.set_active (true);
2319 roll_button.set_active (false);
2324 roll_button.set_active (true);
2325 play_selection_button.set_active (false);
2326 auto_loop_button.set_active (false);
2329 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2330 /* light up both roll and play-selection if they are joined */
2331 roll_button.set_active (true);
2332 play_selection_button.set_active (true);
2335 stop_button.set_active (false);
2339 stop_button.set_active (true);
2340 roll_button.set_active (false);
2341 play_selection_button.set_active (false);
2342 if (Config->get_loop_is_mode ()) {
2343 auto_loop_button.set_active (_session->get_play_loop());
2345 auto_loop_button.set_active (false);
2347 update_disk_space ();
2352 ARDOUR_UI::blink_handler (bool blink_on)
2354 transport_rec_enable_blink (blink_on);
2355 solo_blink (blink_on);
2356 sync_blink (blink_on);
2357 audition_blink (blink_on);
2358 feedback_blink (blink_on);
2359 error_blink (blink_on);
2363 ARDOUR_UI::update_clocks ()
2365 if (!_session) return;
2367 if (editor && !editor->dragging_playhead()) {
2368 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2373 ARDOUR_UI::start_clocking ()
2375 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2376 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2378 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2383 ARDOUR_UI::stop_clocking ()
2385 clock_signal_connection.disconnect ();
2389 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2393 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2395 label->set_text (buf);
2396 bar->set_fraction (fraction);
2398 /* process events, redraws, etc. */
2400 while (gtk_events_pending()) {
2401 gtk_main_iteration ();
2404 return true; /* continue with save-as */
2408 ARDOUR_UI::save_session_as ()
2414 if (!save_as_dialog) {
2415 save_as_dialog = new SaveAsDialog;
2418 save_as_dialog->set_name (_session->name());
2420 int response = save_as_dialog->run ();
2422 save_as_dialog->hide ();
2425 case Gtk::RESPONSE_OK:
2434 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2435 sa.new_name = save_as_dialog->new_name ();
2436 sa.switch_to = save_as_dialog->switch_to();
2437 sa.copy_media = save_as_dialog->copy_media();
2438 sa.copy_external = save_as_dialog->copy_external();
2439 sa.include_media = save_as_dialog->include_media ();
2441 /* Only bother with a progress dialog if we're going to copy
2442 media into the save-as target. Without that choice, this
2443 will be very fast because we're only talking about a few kB's to
2444 perhaps a couple of MB's of data.
2447 ArdourDialog progress_dialog (_("Save As"), true);
2449 if (sa.include_media && sa.copy_media) {
2452 Gtk::ProgressBar progress_bar;
2454 progress_dialog.get_vbox()->pack_start (label);
2455 progress_dialog.get_vbox()->pack_start (progress_bar);
2457 progress_bar.show ();
2459 /* this signal will be emitted from within this, the calling thread,
2460 * after every file is copied. It provides information on percentage
2461 * complete (in terms of total data to copy), the number of files
2462 * copied so far, and the total number to copy.
2467 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2469 progress_dialog.show_all ();
2470 progress_dialog.present ();
2473 if (_session->save_as (sa)) {
2475 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2479 if (!sa.include_media) {
2480 unload_session (false);
2481 load_session (sa.final_session_folder_name, sa.new_name);
2486 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2490 struct tm local_time;
2493 localtime_r (&n, &local_time);
2494 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2496 save_state (timebuf, switch_to_it);
2501 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2505 prompter.get_result (snapname);
2507 bool do_save = (snapname.length() != 0);
2510 char illegal = Session::session_name_is_legal(snapname);
2512 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2513 "snapshot names may not contain a '%1' character"), illegal));
2519 vector<std::string> p;
2520 get_state_files_in_directory (_session->session_directory().root_path(), p);
2521 vector<string> n = get_file_names_no_extension (p);
2523 if (find (n.begin(), n.end(), snapname) != n.end()) {
2525 do_save = overwrite_file_dialog (prompter,
2526 _("Confirm Snapshot Overwrite"),
2527 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2531 save_state (snapname, switch_to_it);
2541 /** Ask the user for the name of a new snapshot and then take it.
2545 ARDOUR_UI::snapshot_session (bool switch_to_it)
2547 ArdourPrompter prompter (true);
2549 prompter.set_name ("Prompter");
2550 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2552 prompter.set_title (_("Save as..."));
2553 prompter.set_prompt (_("New session name"));
2555 prompter.set_title (_("Take Snapshot"));
2556 prompter.set_prompt (_("Name of new snapshot"));
2560 prompter.set_initial_text (_session->snap_name());
2564 struct tm local_time;
2567 localtime_r (&n, &local_time);
2568 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2569 prompter.set_initial_text (timebuf);
2572 bool finished = false;
2574 switch (prompter.run()) {
2575 case RESPONSE_ACCEPT:
2577 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2588 /** Ask the user for a new session name and then rename the session to it.
2592 ARDOUR_UI::rename_session ()
2598 ArdourPrompter prompter (true);
2601 prompter.set_name ("Prompter");
2602 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2603 prompter.set_title (_("Rename Session"));
2604 prompter.set_prompt (_("New session name"));
2607 switch (prompter.run()) {
2608 case RESPONSE_ACCEPT:
2610 prompter.get_result (name);
2612 bool do_rename = (name.length() != 0);
2615 char illegal = Session::session_name_is_legal (name);
2618 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2619 "session names may not contain a '%1' character"), illegal));
2624 switch (_session->rename (name)) {
2626 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2627 msg.set_position (WIN_POS_MOUSE);
2635 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2636 msg.set_position (WIN_POS_MOUSE);
2652 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2654 if (!_session || _session->deletion_in_progress()) {
2658 XMLNode* node = new XMLNode (X_("UI"));
2660 WM::Manager::instance().add_state (*node);
2662 node->add_child_nocopy (gui_object_state->get_state());
2664 _session->add_extra_xml (*node);
2666 if (export_video_dialog) {
2667 _session->add_extra_xml (export_video_dialog->get_state());
2670 save_state_canfail (name, switch_to_it);
2674 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2679 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2684 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2689 ARDOUR_UI::primary_clock_value_changed ()
2692 _session->request_locate (primary_clock->current_time ());
2697 ARDOUR_UI::big_clock_value_changed ()
2700 _session->request_locate (big_clock->current_time ());
2705 ARDOUR_UI::secondary_clock_value_changed ()
2708 _session->request_locate (secondary_clock->current_time ());
2713 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2715 if (_session == 0) {
2719 if (_session->step_editing()) {
2723 Session::RecordState const r = _session->record_status ();
2724 bool const h = _session->have_rec_enabled_track ();
2726 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2728 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2730 rec_button.set_active_state (Gtkmm2ext::Off);
2732 } else if (r == Session::Recording && h) {
2733 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2735 rec_button.unset_active_state ();
2740 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2744 prompter.get_result (name);
2746 if (name.length()) {
2747 int failed = _session->save_template (name);
2749 if (failed == -2) { /* file already exists. */
2750 bool overwrite = overwrite_file_dialog (prompter,
2751 _("Confirm Template Overwrite"),
2752 _("A template already exists with that name. Do you want to overwrite it?"));
2755 _session->save_template (name, true);
2767 ARDOUR_UI::save_template ()
2769 ArdourPrompter prompter (true);
2771 if (!check_audioengine (_main_window)) {
2775 prompter.set_name (X_("Prompter"));
2776 prompter.set_title (_("Save Template"));
2777 prompter.set_prompt (_("Name for template:"));
2778 prompter.set_initial_text(_session->name() + _("-template"));
2779 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2781 bool finished = false;
2783 switch (prompter.run()) {
2784 case RESPONSE_ACCEPT:
2785 finished = process_save_template_prompter (prompter);
2796 ARDOUR_UI::edit_metadata ()
2798 SessionMetadataEditor dialog;
2799 dialog.set_session (_session);
2800 dialog.grab_focus ();
2805 ARDOUR_UI::import_metadata ()
2807 SessionMetadataImporter dialog;
2808 dialog.set_session (_session);
2813 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2815 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2817 MessageDialog msg (str,
2819 Gtk::MESSAGE_WARNING,
2820 Gtk::BUTTONS_YES_NO,
2824 msg.set_name (X_("OpenExistingDialog"));
2825 msg.set_title (_("Open Existing Session"));
2826 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2827 msg.set_position (Gtk::WIN_POS_CENTER);
2828 pop_back_splash (msg);
2830 switch (msg.run()) {
2839 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2841 BusProfile bus_profile;
2845 bus_profile.master_out_channels = 2;
2846 bus_profile.input_ac = AutoConnectPhysical;
2847 bus_profile.output_ac = AutoConnectMaster;
2848 bus_profile.requested_physical_in = 0; // use all available
2849 bus_profile.requested_physical_out = 0; // use all available
2853 /* get settings from advanced section of NSD */
2855 if (sd.create_master_bus()) {
2856 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2858 bus_profile.master_out_channels = 0;
2861 if (sd.connect_inputs()) {
2862 bus_profile.input_ac = AutoConnectPhysical;
2864 bus_profile.input_ac = AutoConnectOption (0);
2867 bus_profile.output_ac = AutoConnectOption (0);
2869 if (sd.connect_outputs ()) {
2870 if (sd.connect_outs_to_master()) {
2871 bus_profile.output_ac = AutoConnectMaster;
2872 } else if (sd.connect_outs_to_physical()) {
2873 bus_profile.output_ac = AutoConnectPhysical;
2877 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2878 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2881 if (build_session (session_path, session_name, bus_profile)) {
2889 ARDOUR_UI::load_from_application_api (const std::string& path)
2891 ARDOUR_COMMAND_LINE::session_name = path;
2892 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2894 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2896 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2897 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2898 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2899 * -> SessionDialog is not displayed
2902 if (_session_dialog) {
2903 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2904 std::string session_path = path;
2905 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2906 session_path = Glib::path_get_dirname (session_path);
2908 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2909 _session_dialog->set_provided_session (session_name, session_path);
2910 _session_dialog->response (RESPONSE_NONE);
2911 _session_dialog->hide();
2916 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2917 /* /path/to/foo => /path/to/foo, foo */
2918 rv = load_session (path, basename_nosuffix (path));
2920 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2921 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2924 // if load_session fails -> pop up SessionDialog.
2926 ARDOUR_COMMAND_LINE::session_name = "";
2928 if (get_session_parameters (true, false)) {
2932 goto_editor_window ();
2936 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2938 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2940 string session_name;
2941 string session_path;
2942 string template_name;
2944 bool likely_new = false;
2945 bool cancel_not_quit;
2947 /* deal with any existing DIRTY session now, rather than later. don't
2948 * treat a non-dirty session this way, so that it stays visible
2949 * as we bring up the new session dialog.
2952 if (_session && ARDOUR_UI::instance()->video_timeline) {
2953 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2956 /* if there is already a session, relabel the button
2957 on the SessionDialog so that we don't Quit directly
2959 cancel_not_quit = (_session != 0);
2961 if (_session && _session->dirty()) {
2962 if (unload_session (false)) {
2963 /* unload cancelled by user */
2966 ARDOUR_COMMAND_LINE::session_name = "";
2969 if (!load_template.empty()) {
2970 should_be_new = true;
2971 template_name = load_template;
2974 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2975 session_path = ARDOUR_COMMAND_LINE::session_name;
2977 if (!session_path.empty()) {
2978 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2979 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2980 /* session/snapshot file, change path to be dir */
2981 session_path = Glib::path_get_dirname (session_path);
2986 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2988 _session_dialog = &session_dialog;
2991 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2993 /* if they named a specific statefile, use it, otherwise they are
2994 just giving a session folder, and we want to use it as is
2995 to find the session.
2998 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3000 if (suffix != string::npos) {
3001 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3002 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3003 session_name = Glib::path_get_basename (session_name);
3005 session_path = ARDOUR_COMMAND_LINE::session_name;
3006 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3011 session_dialog.clear_given ();
3014 if (should_be_new || session_name.empty()) {
3015 /* need the dialog to get info from user */
3017 cerr << "run dialog\n";
3019 switch (session_dialog.run()) {
3020 case RESPONSE_ACCEPT:
3023 /* this is used for async * app->ShouldLoad(). */
3024 continue; // while loop
3027 if (quit_on_cancel) {
3028 // JE - Currently (July 2014) this section can only get reached if the
3029 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3030 // point does NOT indicate an abnormal termination). Therefore, let's
3031 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3033 pthread_cancel_all ();
3041 session_dialog.hide ();
3044 /* if we run the startup dialog again, offer more than just "new session" */
3046 should_be_new = false;
3048 session_name = session_dialog.session_name (likely_new);
3049 session_path = session_dialog.session_folder ();
3055 string::size_type suffix = session_name.find (statefile_suffix);
3057 if (suffix != string::npos) {
3058 session_name = session_name.substr (0, suffix);
3061 /* this shouldn't happen, but we catch it just in case it does */
3063 if (session_name.empty()) {
3067 if (session_dialog.use_session_template()) {
3068 template_name = session_dialog.session_template_name();
3069 _session_is_new = true;
3072 if (session_name[0] == G_DIR_SEPARATOR ||
3073 #ifdef PLATFORM_WINDOWS
3074 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3076 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3077 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3082 /* absolute path or cwd-relative path specified for session name: infer session folder
3083 from what was given.
3086 session_path = Glib::path_get_dirname (session_name);
3087 session_name = Glib::path_get_basename (session_name);
3091 session_path = session_dialog.session_folder();
3093 char illegal = Session::session_name_is_legal (session_name);
3096 MessageDialog msg (session_dialog,
3097 string_compose (_("To ensure compatibility with various systems\n"
3098 "session names may not contain a '%1' character"),
3101 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3106 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3109 if (likely_new && !nsm) {
3111 std::string existing = Glib::build_filename (session_path, session_name);
3113 if (!ask_about_loading_existing_session (existing)) {
3114 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3119 _session_is_new = false;
3124 pop_back_splash (session_dialog);
3125 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3127 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3131 char illegal = Session::session_name_is_legal(session_name);
3134 pop_back_splash (session_dialog);
3135 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3136 "session names may not contain a '%1' character"), illegal));
3138 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3142 _session_is_new = true;
3145 if (likely_new && template_name.empty()) {
3147 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3151 ret = load_session (session_path, session_name, template_name);
3154 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3158 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3159 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3163 /* clear this to avoid endless attempts to load the
3167 ARDOUR_COMMAND_LINE::session_name = "";
3171 _session_dialog = NULL;
3177 ARDOUR_UI::close_session()
3179 if (!check_audioengine (_main_window)) {
3183 if (unload_session (true)) {
3187 ARDOUR_COMMAND_LINE::session_name = "";
3189 if (get_session_parameters (true, false)) {
3194 /** @param snap_name Snapshot name (without .ardour suffix).
3195 * @return -2 if the load failed because we are not connected to the AudioEngine.
3198 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3200 Session *new_session;
3205 unload_status = unload_session ();
3207 if (unload_status < 0) {
3209 } else if (unload_status > 0) {
3215 session_loaded = false;
3217 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3220 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3223 /* this one is special */
3225 catch (AudioEngine::PortRegistrationFailure& err) {
3227 MessageDialog msg (err.what(),
3230 Gtk::BUTTONS_CLOSE);
3232 msg.set_title (_("Port Registration Error"));
3233 msg.set_secondary_text (_("Click the Close button to try again."));
3234 msg.set_position (Gtk::WIN_POS_CENTER);
3235 pop_back_splash (msg);
3238 int response = msg.run ();
3243 case RESPONSE_CANCEL:
3250 catch (SessionException e) {
3251 MessageDialog msg (string_compose(
3252 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3253 path, snap_name, e.what()),
3258 msg.set_title (_("Loading Error"));
3259 msg.set_position (Gtk::WIN_POS_CENTER);
3260 pop_back_splash (msg);
3272 MessageDialog msg (string_compose(
3273 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3279 msg.set_title (_("Loading Error"));
3280 msg.set_position (Gtk::WIN_POS_CENTER);
3281 pop_back_splash (msg);
3293 list<string> const u = new_session->unknown_processors ();
3295 MissingPluginDialog d (_session, u);
3300 if (!new_session->writable()) {
3301 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3306 msg.set_title (_("Read-only Session"));
3307 msg.set_position (Gtk::WIN_POS_CENTER);
3308 pop_back_splash (msg);
3315 /* Now the session been created, add the transport controls */
3316 new_session->add_controllable(roll_controllable);
3317 new_session->add_controllable(stop_controllable);
3318 new_session->add_controllable(goto_start_controllable);
3319 new_session->add_controllable(goto_end_controllable);
3320 new_session->add_controllable(auto_loop_controllable);
3321 new_session->add_controllable(play_selection_controllable);
3322 new_session->add_controllable(rec_controllable);
3324 set_session (new_session);
3326 session_loaded = true;
3329 _session->set_clean ();
3332 #ifdef WINDOWS_VST_SUPPORT
3333 fst_stop_threading();
3337 Timers::TimerSuspender t;
3341 #ifdef WINDOWS_VST_SUPPORT
3342 fst_start_threading();
3351 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3353 Session *new_session;
3356 session_loaded = false;
3357 x = unload_session ();
3365 _session_is_new = true;
3368 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3371 catch (SessionException e) {
3373 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3374 msg.set_title (_("Loading Error"));
3375 msg.set_position (Gtk::WIN_POS_CENTER);
3376 pop_back_splash (msg);
3382 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3383 msg.set_title (_("Loading Error"));
3384 msg.set_position (Gtk::WIN_POS_CENTER);
3385 pop_back_splash (msg);
3390 /* Give the new session the default GUI state, if such things exist */
3393 n = Config->instant_xml (X_("Editor"));
3395 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3396 new_session->add_instant_xml (*n, false);
3398 n = Config->instant_xml (X_("Mixer"));
3400 new_session->add_instant_xml (*n, false);
3403 /* Put the playhead at 0 and scroll fully left */
3404 n = new_session->instant_xml (X_("Editor"));
3406 n->add_property (X_("playhead"), X_("0"));
3407 n->add_property (X_("left-frame"), X_("0"));
3410 set_session (new_session);
3412 session_loaded = true;
3414 new_session->save_state(new_session->name());
3420 ARDOUR_UI::launch_chat ()
3422 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3424 dialog.set_title (_("About the Chat"));
3425 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."));
3427 switch (dialog.run()) {
3430 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3431 #elif defined PLATFORM_WINDOWS
3432 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3434 open_uri("http://webchat.freenode.net/?channels=ardour");
3443 ARDOUR_UI::launch_manual ()
3445 PBD::open_uri (Config->get_tutorial_manual_url());
3449 ARDOUR_UI::launch_reference ()
3451 PBD::open_uri (Config->get_reference_manual_url());
3455 ARDOUR_UI::launch_tracker ()
3457 PBD::open_uri ("http://tracker.ardour.org");
3461 ARDOUR_UI::launch_subscribe ()
3463 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3467 ARDOUR_UI::launch_cheat_sheet ()
3470 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3472 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3477 ARDOUR_UI::launch_website ()
3479 PBD::open_uri ("http://ardour.org");
3483 ARDOUR_UI::launch_website_dev ()
3485 PBD::open_uri ("http://ardour.org/development.html");
3489 ARDOUR_UI::launch_forums ()
3491 PBD::open_uri ("https://community.ardour.org/forums");
3495 ARDOUR_UI::launch_howto_report ()
3497 PBD::open_uri ("http://ardour.org/reporting_bugs");
3501 ARDOUR_UI::loading_message (const std::string& msg)
3503 if (ARDOUR_COMMAND_LINE::no_splash) {
3511 splash->message (msg);
3515 ARDOUR_UI::show_splash ()
3519 splash = new Splash;
3529 ARDOUR_UI::hide_splash ()
3536 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3540 removed = rep.paths.size();
3543 MessageDialog msgd (_main_window,
3544 _("No files were ready for clean-up"),
3548 msgd.set_title (_("Clean-up"));
3549 msgd.set_secondary_text (_("If this seems suprising, \n\
3550 check for any existing snapshots.\n\
3551 These may still include regions that\n\
3552 require some unused files to continue to exist."));
3558 ArdourDialog results (_("Clean-up"), true, false);
3560 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3561 CleanupResultsModelColumns() {
3565 Gtk::TreeModelColumn<std::string> visible_name;
3566 Gtk::TreeModelColumn<std::string> fullpath;
3570 CleanupResultsModelColumns results_columns;
3571 Glib::RefPtr<Gtk::ListStore> results_model;
3572 Gtk::TreeView results_display;
3574 results_model = ListStore::create (results_columns);
3575 results_display.set_model (results_model);
3576 results_display.append_column (list_title, results_columns.visible_name);
3578 results_display.set_name ("CleanupResultsList");
3579 results_display.set_headers_visible (true);
3580 results_display.set_headers_clickable (false);
3581 results_display.set_reorderable (false);
3583 Gtk::ScrolledWindow list_scroller;
3586 Gtk::HBox dhbox; // the hbox for the image and text
3587 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3588 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3590 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3592 const string dead_directory = _session->session_directory().dead_path();
3595 %1 - number of files removed
3596 %2 - location of "dead"
3597 %3 - size of files affected
3598 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3601 const char* bprefix;
3602 double space_adjusted = 0;
3604 if (rep.space < 1000) {
3606 space_adjusted = rep.space;
3607 } else if (rep.space < 1000000) {
3608 bprefix = _("kilo");
3609 space_adjusted = floorf((float)rep.space / 1000.0);
3610 } else if (rep.space < 1000000 * 1000) {
3611 bprefix = _("mega");
3612 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3614 bprefix = _("giga");
3615 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3619 txt.set_markup (string_compose (P_("\
3620 The following file was deleted from %2,\n\
3621 releasing %3 %4bytes of disk space", "\
3622 The following %1 files were deleted from %2,\n\
3623 releasing %3 %4bytes of disk space", removed),
3624 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3626 txt.set_markup (string_compose (P_("\
3627 The following file was not in use and \n\
3628 has been moved to: %2\n\n\
3629 After a restart of %5\n\n\
3630 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3631 will release an additional %3 %4bytes of disk space.\n", "\
3632 The following %1 files were not in use and \n\
3633 have been moved to: %2\n\n\
3634 After a restart of %5\n\n\
3635 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3636 will release an additional %3 %4bytes of disk space.\n", removed),
3637 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3640 dhbox.pack_start (*dimage, true, false, 5);
3641 dhbox.pack_start (txt, true, false, 5);
3643 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3644 TreeModel::Row row = *(results_model->append());
3645 row[results_columns.visible_name] = *i;
3646 row[results_columns.fullpath] = *i;
3649 list_scroller.add (results_display);
3650 list_scroller.set_size_request (-1, 150);
3651 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3653 dvbox.pack_start (dhbox, true, false, 5);
3654 dvbox.pack_start (list_scroller, true, false, 5);
3655 ddhbox.pack_start (dvbox, true, false, 5);
3657 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3658 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3659 results.set_default_response (RESPONSE_CLOSE);
3660 results.set_position (Gtk::WIN_POS_MOUSE);
3662 results_display.show();
3663 list_scroller.show();
3670 //results.get_vbox()->show();
3671 results.set_resizable (false);
3678 ARDOUR_UI::cleanup ()
3680 if (_session == 0) {
3681 /* shouldn't happen: menu item is insensitive */
3686 MessageDialog checker (_("Are you sure you want to clean-up?"),
3688 Gtk::MESSAGE_QUESTION,
3691 checker.set_title (_("Clean-up"));
3693 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3694 ALL undo/redo information will be lost if you clean-up.\n\
3695 Clean-up will move all unused files to a \"dead\" location."));
3697 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3698 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3699 checker.set_default_response (RESPONSE_CANCEL);
3701 checker.set_name (_("CleanupDialog"));
3702 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3703 checker.set_position (Gtk::WIN_POS_MOUSE);
3705 switch (checker.run()) {
3706 case RESPONSE_ACCEPT:
3712 ARDOUR::CleanupReport rep;
3714 editor->prepare_for_cleanup ();
3716 /* do not allow flush until a session is reloaded */
3718 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3720 act->set_sensitive (false);
3723 if (_session->cleanup_sources (rep)) {
3724 editor->finish_cleanup ();
3728 editor->finish_cleanup ();
3731 display_cleanup_results (rep, _("Cleaned Files"), false);
3735 ARDOUR_UI::flush_trash ()
3737 if (_session == 0) {
3738 /* shouldn't happen: menu item is insensitive */
3742 ARDOUR::CleanupReport rep;
3744 if (_session->cleanup_trash_sources (rep)) {
3748 display_cleanup_results (rep, _("deleted file"), true);
3752 ARDOUR_UI::cleanup_peakfiles ()
3754 if (_session == 0) {
3755 /* shouldn't happen: menu item is insensitive */
3759 if (! _session->can_cleanup_peakfiles ()) {
3763 // get all region-views in this session
3765 TrackViewList empty;
3767 editor->get_regions_after(rs, (framepos_t) 0, empty);
3768 std::list<RegionView*> views = rs.by_layer();
3770 // remove displayed audio-region-views waveforms
3771 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3772 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3773 if (!arv) { continue ; }
3774 arv->delete_waves();
3777 // cleanup peak files:
3778 // - stop pending peakfile threads
3779 // - close peakfiles if any
3780 // - remove peak dir in session
3781 // - setup peakfiles (background thread)
3782 _session->cleanup_peakfiles ();
3784 // re-add waves to ARV
3785 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3786 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3787 if (!arv) { continue ; }
3788 arv->create_waves();
3793 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3795 uint32_t order_hint = UINT32_MAX;
3797 if (editor->get_selection().tracks.empty()) {
3802 we want the new routes to have their order keys set starting from
3803 the highest order key in the selection + 1 (if available).
3806 if (place == AddRouteDialog::AfterSelection) {
3807 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3809 order_hint = rtav->route()->order_key();
3812 } else if (place == AddRouteDialog::BeforeSelection) {
3813 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3815 order_hint = rtav->route()->order_key();
3817 } else if (place == AddRouteDialog::First) {
3820 /* leave order_hint at UINT32_MAX */
3823 if (order_hint == UINT32_MAX) {
3824 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3825 * not setting an order hint will place new routes last.
3830 _session->set_order_hint (order_hint);
3832 /* create a gap in the existing route order keys to accomodate new routes.*/
3833 boost::shared_ptr <RouteList> rd = _session->get_routes();
3834 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3835 boost::shared_ptr<Route> rt (*ri);
3837 if (rt->is_monitor()) {
3841 if (rt->order_key () >= order_hint) {
3842 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3848 ARDOUR_UI::start_duplicate_routes ()
3850 if (!duplicate_routes_dialog) {
3851 duplicate_routes_dialog = new DuplicateRouteDialog;
3854 if (duplicate_routes_dialog->restart (_session)) {
3858 duplicate_routes_dialog->present ();
3862 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3870 if (add_route_dialog->is_visible()) {
3871 /* we're already doing this */
3875 ResponseType r = (ResponseType) add_route_dialog->run ();
3877 add_route_dialog->hide();
3880 case RESPONSE_ACCEPT:
3887 if ((count = add_route_dialog->count()) <= 0) {
3891 setup_order_hint(add_route_dialog->insert_at());
3893 string template_path = add_route_dialog->track_template();
3894 DisplaySuspender ds;
3896 if (!template_path.empty()) {
3897 if (add_route_dialog->name_template_is_default()) {
3898 _session->new_route_from_template (count, template_path, string());
3900 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3905 ChanCount input_chan= add_route_dialog->channels ();
3906 ChanCount output_chan;
3907 string name_template = add_route_dialog->name_template ();
3908 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3909 RouteGroup* route_group = add_route_dialog->route_group ();
3910 AutoConnectOption oac = Config->get_output_auto_connect();
3912 if (oac & AutoConnectMaster) {
3913 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3914 output_chan.set (DataType::MIDI, 0);
3916 output_chan = input_chan;
3919 /* XXX do something with name template */
3921 switch (add_route_dialog->type_wanted()) {
3922 case AddRouteDialog::AudioTrack:
3923 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3925 case AddRouteDialog::MidiTrack:
3926 session_add_midi_track (route_group, count, name_template, instrument);
3928 case AddRouteDialog::MixedTrack:
3929 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3931 case AddRouteDialog::AudioBus:
3932 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3938 ARDOUR_UI::stop_video_server (bool ask_confirm)
3940 if (!video_server_process && ask_confirm) {
3941 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3943 if (video_server_process) {
3945 ArdourDialog confirm (_("Stop Video-Server"), true);
3946 Label m (_("Do you really want to stop the Video Server?"));
3947 confirm.get_vbox()->pack_start (m, true, true);
3948 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3949 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3950 confirm.show_all ();
3951 if (confirm.run() == RESPONSE_CANCEL) {
3955 delete video_server_process;
3956 video_server_process =0;
3961 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3963 ARDOUR_UI::start_video_server( float_window, true);
3967 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3973 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3974 if (video_server_process) {
3975 popup_error(_("The Video Server is already started."));
3977 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3983 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3985 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3987 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3989 video_server_dialog->set_transient_for (*float_window);
3992 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3993 video_server_dialog->hide();
3995 ResponseType r = (ResponseType) video_server_dialog->run ();
3996 video_server_dialog->hide();
3997 if (r != RESPONSE_ACCEPT) { return false; }
3998 if (video_server_dialog->show_again()) {
3999 Config->set_show_video_server_dialog(false);
4003 std::string icsd_exec = video_server_dialog->get_exec_path();
4004 std::string icsd_docroot = video_server_dialog->get_docroot();
4005 if (icsd_docroot.empty()) {
4006 #ifndef PLATFORM_WINDOWS
4007 icsd_docroot = X_("/");
4009 icsd_docroot = X_("C:\\");
4014 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4015 warning << _("Specified docroot is not an existing directory.") << endmsg;
4018 #ifndef PLATFORM_WINDOWS
4019 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4020 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4021 warning << _("Given Video Server is not an executable file.") << endmsg;
4025 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4026 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4027 warning << _("Given Video Server is not an executable file.") << endmsg;
4033 argp=(char**) calloc(9,sizeof(char*));
4034 argp[0] = strdup(icsd_exec.c_str());
4035 argp[1] = strdup("-P");
4036 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4037 argp[3] = strdup("-p");
4038 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4039 argp[5] = strdup("-C");
4040 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4041 argp[7] = strdup(icsd_docroot.c_str());
4043 stop_video_server();
4045 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4046 Config->set_video_advanced_setup(false);
4048 std::ostringstream osstream;
4049 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4050 Config->set_video_server_url(osstream.str());
4051 Config->set_video_server_docroot(icsd_docroot);
4052 Config->set_video_advanced_setup(true);
4055 if (video_server_process) {
4056 delete video_server_process;
4059 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4060 if (video_server_process->start()) {
4061 warning << _("Cannot launch the video-server") << endmsg;
4064 int timeout = 120; // 6 sec
4065 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4066 Glib::usleep (50000);
4068 if (--timeout <= 0 || !video_server_process->is_running()) break;
4071 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4073 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4074 delete video_server_process;
4075 video_server_process = 0;
4083 ARDOUR_UI::add_video (Gtk::Window* float_window)
4089 if (!start_video_server(float_window, false)) {
4090 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4095 add_video_dialog->set_transient_for (*float_window);
4098 if (add_video_dialog->is_visible()) {
4099 /* we're already doing this */
4103 ResponseType r = (ResponseType) add_video_dialog->run ();
4104 add_video_dialog->hide();
4105 if (r != RESPONSE_ACCEPT) { return; }
4107 bool local_file, orig_local_file;
4108 std::string path = add_video_dialog->file_name(local_file);
4110 std::string orig_path = path;
4111 orig_local_file = local_file;
4113 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4115 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4116 warning << string_compose(_("could not open %1"), path) << endmsg;
4119 if (!local_file && path.length() == 0) {
4120 warning << _("no video-file selected") << endmsg;
4124 std::string audio_from_video;
4125 bool detect_ltc = false;
4127 switch (add_video_dialog->import_option()) {
4128 case VTL_IMPORT_TRANSCODE:
4130 TranscodeVideoDialog *transcode_video_dialog;
4131 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4132 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4133 transcode_video_dialog->hide();
4134 if (r != RESPONSE_ACCEPT) {
4135 delete transcode_video_dialog;
4139 audio_from_video = transcode_video_dialog->get_audiofile();
4141 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4144 else if (!audio_from_video.empty()) {
4145 editor->embed_audio_from_video(
4147 video_timeline->get_offset(),
4148 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4151 switch (transcode_video_dialog->import_option()) {
4152 case VTL_IMPORT_TRANSCODED:
4153 path = transcode_video_dialog->get_filename();
4156 case VTL_IMPORT_REFERENCE:
4159 delete transcode_video_dialog;
4162 delete transcode_video_dialog;
4166 case VTL_IMPORT_NONE:
4170 /* strip _session->session_directory().video_path() from video file if possible */
4171 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4172 path=path.substr(_session->session_directory().video_path().size());
4173 if (path.at(0) == G_DIR_SEPARATOR) {
4174 path=path.substr(1);
4178 video_timeline->set_update_session_fps(auto_set_session_fps);
4180 if (video_timeline->video_file_info(path, local_file)) {
4181 XMLNode* node = new XMLNode(X_("Videotimeline"));
4182 node->add_property (X_("Filename"), path);
4183 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4184 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4185 if (orig_local_file) {
4186 node->add_property (X_("OriginalVideoFile"), orig_path);
4188 node->remove_property (X_("OriginalVideoFile"));
4190 _session->add_extra_xml (*node);
4191 _session->set_dirty ();
4193 if (!audio_from_video.empty() && detect_ltc) {
4194 std::vector<LTCFileReader::LTCMap> ltc_seq;
4197 /* TODO ask user about TV standard (LTC alignment if any) */
4198 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4199 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4201 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4203 /* TODO seek near end of file, and read LTC until end.
4204 * if it fails to find any LTC frames, scan complete file
4206 * calculate drift of LTC compared to video-duration,
4207 * ask user for reference (timecode from start/mid/end)
4210 // LTCFileReader will have written error messages
4213 ::g_unlink(audio_from_video.c_str());
4215 if (ltc_seq.size() == 0) {
4216 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4218 /* the very first TC in the file is somteimes not aligned properly */
4219 int i = ltc_seq.size() -1;
4220 ARDOUR::frameoffset_t video_start_offset =
4221 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4222 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4223 video_timeline->set_offset(video_start_offset);
4227 _session->maybe_update_session_range(
4228 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4229 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4232 if (add_video_dialog->launch_xjadeo() && local_file) {
4233 editor->set_xjadeo_sensitive(true);
4234 editor->toggle_xjadeo_proc(1);
4236 editor->toggle_xjadeo_proc(0);
4238 editor->toggle_ruler_video(true);
4243 ARDOUR_UI::remove_video ()
4245 video_timeline->close_session();
4246 editor->toggle_ruler_video(false);
4249 video_timeline->set_offset_locked(false);
4250 video_timeline->set_offset(0);
4252 /* delete session state */
4253 XMLNode* node = new XMLNode(X_("Videotimeline"));
4254 _session->add_extra_xml(*node);
4255 node = new XMLNode(X_("Videomonitor"));
4256 _session->add_extra_xml(*node);
4257 node = new XMLNode(X_("Videoexport"));
4258 _session->add_extra_xml(*node);
4259 stop_video_server();
4263 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4265 if (localcacheonly) {
4266 video_timeline->vmon_update();
4268 video_timeline->flush_cache();
4270 editor->queue_visual_videotimeline_update();
4274 ARDOUR_UI::export_video (bool range)
4276 if (ARDOUR::Config->get_show_video_export_info()) {
4277 ExportVideoInfobox infobox (_session);
4278 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4279 if (infobox.show_again()) {
4280 ARDOUR::Config->set_show_video_export_info(false);
4283 case GTK_RESPONSE_YES:
4284 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4290 export_video_dialog->set_session (_session);
4291 export_video_dialog->apply_state(editor->get_selection().time, range);
4292 export_video_dialog->run ();
4293 export_video_dialog->hide ();
4297 ARDOUR_UI::mixer_settings () const
4302 node = _session->instant_xml(X_("Mixer"));
4304 node = Config->instant_xml(X_("Mixer"));
4308 node = new XMLNode (X_("Mixer"));
4315 ARDOUR_UI::main_window_settings () const
4320 node = _session->instant_xml(X_("Main"));
4322 node = Config->instant_xml(X_("Main"));
4326 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4327 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4332 node = new XMLNode (X_("Main"));
4339 ARDOUR_UI::editor_settings () const
4344 node = _session->instant_xml(X_("Editor"));
4346 node = Config->instant_xml(X_("Editor"));
4350 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4351 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4356 node = new XMLNode (X_("Editor"));
4363 ARDOUR_UI::keyboard_settings () const
4367 node = Config->extra_xml(X_("Keyboard"));
4370 node = new XMLNode (X_("Keyboard"));
4377 ARDOUR_UI::create_xrun_marker (framepos_t where)
4380 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4381 _session->locations()->add (location);
4386 ARDOUR_UI::halt_on_xrun_message ()
4388 cerr << "HALT on xrun\n";
4389 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4394 ARDOUR_UI::xrun_handler (framepos_t where)
4400 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4402 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4403 create_xrun_marker(where);
4406 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4407 halt_on_xrun_message ();
4412 ARDOUR_UI::disk_overrun_handler ()
4414 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4416 if (!have_disk_speed_dialog_displayed) {
4417 have_disk_speed_dialog_displayed = true;
4418 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4419 The disk system on your computer\n\
4420 was not able to keep up with %1.\n\
4422 Specifically, it failed to write data to disk\n\
4423 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4424 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4430 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4431 static MessageDialog *scan_dlg = NULL;
4432 static ProgressBar *scan_pbar = NULL;
4433 static HBox *scan_tbox = NULL;
4434 static Gtk::Button *scan_timeout_button;
4437 ARDOUR_UI::cancel_plugin_scan ()
4439 PluginManager::instance().cancel_plugin_scan();
4443 ARDOUR_UI::cancel_plugin_timeout ()
4445 PluginManager::instance().cancel_plugin_timeout();
4446 scan_timeout_button->set_sensitive (false);
4450 ARDOUR_UI::plugin_scan_timeout (int timeout)
4452 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4456 scan_pbar->set_sensitive (false);
4457 scan_timeout_button->set_sensitive (true);
4458 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4461 scan_pbar->set_sensitive (false);
4462 scan_timeout_button->set_sensitive (false);
4468 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4470 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4474 const bool cancelled = PluginManager::instance().cancelled();
4475 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4476 if (cancelled && scan_dlg->is_mapped()) {
4481 if (cancelled || !can_cancel) {
4486 static Gtk::Button *cancel_button;
4488 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4489 VBox* vbox = scan_dlg->get_vbox();
4490 vbox->set_size_request(400,-1);
4491 scan_dlg->set_title (_("Scanning for plugins"));
4493 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4494 cancel_button->set_name ("EditorGTKButton");
4495 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4496 cancel_button->show();
4498 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4500 scan_tbox = manage( new HBox() );
4502 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4503 scan_timeout_button->set_name ("EditorGTKButton");
4504 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4505 scan_timeout_button->show();
4507 scan_pbar = manage(new ProgressBar());
4508 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4509 scan_pbar->set_text(_("Scan Timeout"));
4512 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4513 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4515 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4518 assert(scan_dlg && scan_tbox && cancel_button);
4520 if (type == X_("closeme")) {
4524 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4527 if (!can_cancel || !cancelled) {
4528 scan_timeout_button->set_sensitive(false);
4530 cancel_button->set_sensitive(can_cancel && !cancelled);
4536 ARDOUR_UI::gui_idle_handler ()
4539 /* due to idle calls, gtk_events_pending() may always return true */
4540 while (gtk_events_pending() && --timeout) {
4541 gtk_main_iteration ();
4546 ARDOUR_UI::disk_underrun_handler ()
4548 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4550 if (!have_disk_speed_dialog_displayed) {
4551 have_disk_speed_dialog_displayed = true;
4552 MessageDialog* msg = new MessageDialog (
4553 _main_window, string_compose (_("The disk system on your computer\n\
4554 was not able to keep up with %1.\n\
4556 Specifically, it failed to read data from disk\n\
4557 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4558 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4564 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4566 have_disk_speed_dialog_displayed = false;
4571 ARDOUR_UI::session_dialog (std::string msg)
4573 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4577 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4584 ARDOUR_UI::pending_state_dialog ()
4586 HBox* hbox = manage (new HBox());
4587 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4588 ArdourDialog dialog (_("Crash Recovery"), true);
4589 Label message (string_compose (_("\
4590 This session appears to have been in the\n\
4591 middle of recording when %1 or\n\
4592 the computer was shutdown.\n\
4594 %1 can recover any captured audio for\n\
4595 you, or it can ignore it. Please decide\n\
4596 what you would like to do.\n"), PROGRAM_NAME));
4597 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4598 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4599 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4600 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4601 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4602 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4603 dialog.set_default_response (RESPONSE_ACCEPT);
4604 dialog.set_position (WIN_POS_CENTER);
4609 switch (dialog.run ()) {
4610 case RESPONSE_ACCEPT:
4618 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4620 HBox* hbox = new HBox();
4621 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4622 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4623 Label message (string_compose (_("\
4624 This session was created with a sample rate of %1 Hz, but\n\
4625 %2 is currently running at %3 Hz. If you load this session,\n\
4626 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4628 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4629 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4630 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4631 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4632 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4633 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4634 dialog.set_default_response (RESPONSE_ACCEPT);
4635 dialog.set_position (WIN_POS_CENTER);
4640 switch (dialog.run()) {
4641 case RESPONSE_ACCEPT:
4651 ARDOUR_UI::use_config ()
4653 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4655 set_transport_controllable_state (*node);
4660 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4662 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4663 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4665 primary_clock->set (pos);
4668 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4669 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4671 secondary_clock->set (pos);
4674 if (big_clock_window) {
4675 big_clock->set (pos);
4677 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4681 ARDOUR_UI::step_edit_status_change (bool yn)
4683 // XXX should really store pre-step edit status of things
4684 // we make insensitive
4687 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4688 rec_button.set_sensitive (false);
4690 rec_button.unset_active_state ();;
4691 rec_button.set_sensitive (true);
4696 ARDOUR_UI::record_state_changed ()
4698 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4700 if (!_session || !big_clock_window) {
4701 /* why bother - the clock isn't visible */
4705 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4706 big_clock->set_active (true);
4708 big_clock->set_active (false);
4713 ARDOUR_UI::first_idle ()
4716 _session->allow_auto_play (true);
4720 editor->first_idle();
4723 Keyboard::set_can_save_keybindings (true);
4728 ARDOUR_UI::store_clock_modes ()
4730 XMLNode* node = new XMLNode(X_("ClockModes"));
4732 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4733 XMLNode* child = new XMLNode (X_("Clock"));
4735 child->add_property (X_("name"), (*x)->name());
4736 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4737 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4739 node->add_child_nocopy (*child);
4742 _session->add_extra_xml (*node);
4743 _session->set_dirty ();
4746 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4747 : Controllable (name), ui (u), type(tp)
4753 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4756 /* do nothing: these are radio-style actions */
4760 const char *action = 0;
4764 action = X_("Roll");
4767 action = X_("Stop");
4770 action = X_("GotoStart");
4773 action = X_("GotoEnd");
4776 action = X_("Loop");
4779 action = X_("PlaySelection");
4782 action = X_("Record");
4792 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4800 ARDOUR_UI::TransportControllable::get_value (void) const
4827 ARDOUR_UI::setup_profile ()
4829 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4830 Profile->set_small_screen ();
4833 if (g_getenv ("TRX")) {
4834 Profile->set_trx ();
4837 if (g_getenv ("MIXBUS")) {
4838 Profile->set_mixbus ();
4843 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4845 MissingFileDialog dialog (s, str, type);
4850 int result = dialog.run ();
4857 return 1; // quit entire session load
4860 result = dialog.get_action ();
4866 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4868 AmbiguousFileDialog dialog (file, hits);
4875 return dialog.get_which ();
4878 /** Allocate our thread-local buffers */
4880 ARDOUR_UI::get_process_buffers ()
4882 _process_thread->get_buffers ();
4885 /** Drop our thread-local buffers */
4887 ARDOUR_UI::drop_process_buffers ()
4889 _process_thread->drop_buffers ();
4893 ARDOUR_UI::feedback_detected ()
4895 _feedback_exists = true;
4899 ARDOUR_UI::successful_graph_sort ()
4901 _feedback_exists = false;
4905 ARDOUR_UI::midi_panic ()
4908 _session->midi_panic();
4913 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4915 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4916 const char* end_big = "</span>";
4917 const char* start_mono = "<tt>";
4918 const char* end_mono = "</tt>";
4920 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4921 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4922 "From now on, use the -2000 version with older versions of %3"),
4923 xml_path, backup_path, PROGRAM_NAME,
4925 start_mono, end_mono), true);
4932 ARDOUR_UI::reset_peak_display ()
4934 if (!_session || !_session->master_out() || !editor_meter) return;
4935 editor_meter->clear_meters();
4936 editor_meter_max_peak = -INFINITY;
4937 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4941 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4943 if (!_session || !_session->master_out()) return;
4944 if (group == _session->master_out()->route_group()) {
4945 reset_peak_display ();
4950 ARDOUR_UI::reset_route_peak_display (Route* route)
4952 if (!_session || !_session->master_out()) return;
4953 if (_session->master_out().get() == route) {
4954 reset_peak_display ();
4959 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4961 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4962 audio_midi_setup->set_position (WIN_POS_CENTER);
4967 response = audio_midi_setup->run();
4969 case Gtk::RESPONSE_OK:
4970 if (!AudioEngine::instance()->running()) {
4984 ARDOUR_UI::transport_numpad_timeout ()
4986 _numpad_locate_happening = false;
4987 if (_numpad_timeout_connection.connected() )
4988 _numpad_timeout_connection.disconnect();
4993 ARDOUR_UI::transport_numpad_decimal ()
4995 _numpad_timeout_connection.disconnect();
4997 if (_numpad_locate_happening) {
4998 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4999 _numpad_locate_happening = false;
5001 _pending_locate_num = 0;
5002 _numpad_locate_happening = true;
5003 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5008 ARDOUR_UI::transport_numpad_event (int num)
5010 if ( _numpad_locate_happening ) {
5011 _pending_locate_num = _pending_locate_num*10 + num;
5014 case 0: toggle_roll(false, false); break;
5015 case 1: transport_rewind(1); break;
5016 case 2: transport_forward(1); break;
5017 case 3: transport_record(true); break;
5018 case 4: toggle_session_auto_loop(); break;
5019 case 5: transport_record(false); toggle_session_auto_loop(); break;
5020 case 6: toggle_punch(); break;
5021 case 7: toggle_click(); break;
5022 case 8: toggle_auto_return(); break;
5023 case 9: toggle_follow_edits(); break;
5029 ARDOUR_UI::set_flat_buttons ()
5031 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5035 ARDOUR_UI::audioengine_became_silent ()
5037 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5039 Gtk::MESSAGE_WARNING,
5043 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5045 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5046 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5047 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5048 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5049 Gtk::HBox pay_button_box;
5050 Gtk::HBox subscribe_button_box;
5052 pay_button_box.pack_start (pay_button, true, false);
5053 subscribe_button_box.pack_start (subscribe_button, true, false);
5055 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 */
5057 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5058 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5060 msg.get_vbox()->pack_start (pay_label);
5061 msg.get_vbox()->pack_start (pay_button_box);
5062 msg.get_vbox()->pack_start (subscribe_label);
5063 msg.get_vbox()->pack_start (subscribe_button_box);
5065 msg.get_vbox()->show_all ();
5067 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5068 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5069 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5074 case Gtk::RESPONSE_YES:
5075 AudioEngine::instance()->reset_silence_countdown ();
5078 case Gtk::RESPONSE_NO:
5080 save_state_canfail ("");
5084 case Gtk::RESPONSE_CANCEL:
5086 /* don't reset, save session and exit */
5092 ARDOUR_UI::hide_application ()
5094 Application::instance ()-> hide ();
5098 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5100 /* icons, titles, WM stuff */
5102 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5104 if (window_icons.empty()) {
5105 Glib::RefPtr<Gdk::Pixbuf> icon;
5106 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5107 window_icons.push_back (icon);
5109 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5110 window_icons.push_back (icon);
5112 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5113 window_icons.push_back (icon);
5115 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5116 window_icons.push_back (icon);
5120 if (!window_icons.empty()) {
5121 window.set_default_icon_list (window_icons);
5124 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5126 if (!name.empty()) {
5130 window.set_title (title.get_string());
5131 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5133 window.set_flags (CAN_FOCUS);
5134 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5136 /* This is a hack to ensure that GTK-accelerators continue to
5137 * work. Once we switch over to entirely native bindings, this will be
5138 * unnecessary and should be removed
5140 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5142 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5143 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5144 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5145 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5149 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5151 Gtkmm2ext::Bindings* bindings = 0;
5152 Gtk::Window* window = 0;
5154 /* until we get ardour bindings working, we are not handling key
5158 if (ev->type != GDK_KEY_PRESS) {
5162 if (event_window == &_main_window) {
5164 window = event_window;
5166 /* find current tab contents */
5168 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5170 /* see if it uses the ardour binding system */
5173 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5176 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5180 window = event_window;
5182 /* see if window uses ardour binding system */
5184 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5187 /* An empty binding set is treated as if it doesn't exist */
5189 if (bindings && bindings->empty()) {
5193 return key_press_focus_accelerator_handler (*window, ev, bindings);
5197 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5199 GtkWindow* win = window.gobj();
5200 GtkWidget* focus = gtk_window_get_focus (win);
5201 bool special_handling_of_unmodified_accelerators = false;
5202 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5206 /* some widget has keyboard focus */
5208 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5210 /* A particular kind of focusable widget currently has keyboard
5211 * focus. All unmodified key events should go to that widget
5212 * first and not be used as an accelerator by default
5215 special_handling_of_unmodified_accelerators = true;
5219 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 mods ? %8\n",
5222 show_gdk_event_state (ev->state),
5223 special_handling_of_unmodified_accelerators,
5224 Keyboard::some_magic_widget_has_focus(),
5226 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
5227 ((ev->state & mask) ? "yes" : "no")));
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