2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "gtk2ardour-config.h"
22 #include "gtk2ardour-version.h"
32 #ifndef PLATFORM_WINDOWS
33 #include <sys/resource.h>
43 #include "pbd/gstdio_compat.h"
45 #include <gtkmm/messagedialog.h>
46 #include <gtkmm/accelmap.h>
48 #include "pbd/error.h"
49 #include "pbd/basename.h"
50 #include "pbd/compose.h"
51 #include "pbd/convert.h"
52 #include "pbd/failed_constructor.h"
53 #include "pbd/enumwriter.h"
54 #include "pbd/memento_command.h"
55 #include "pbd/openuri.h"
56 #include "pbd/stl_delete.h"
57 #include "pbd/file_utils.h"
58 #include "pbd/localtime_r.h"
59 #include "pbd/pthread_utils.h"
60 #include "pbd/replace_all.h"
61 #include "pbd/xml++.h"
63 #include "gtkmm2ext/application.h"
64 #include "gtkmm2ext/bindings.h"
65 #include "gtkmm2ext/gtk_ui.h"
66 #include "gtkmm2ext/utils.h"
67 #include "gtkmm2ext/click_box.h"
68 #include "gtkmm2ext/fastmeter.h"
69 #include "gtkmm2ext/popup.h"
70 #include "gtkmm2ext/window_title.h"
72 #include "ardour/ardour.h"
73 #include "ardour/audio_backend.h"
74 #include "ardour/audioengine.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/automation_watch.h"
77 #include "ardour/diskstream.h"
78 #include "ardour/filename_extensions.h"
79 #include "ardour/filesystem_paths.h"
80 #include "ardour/ltc_file_reader.h"
81 #include "ardour/port.h"
82 #include "ardour/plugin_manager.h"
83 #include "ardour/process_thread.h"
84 #include "ardour/profile.h"
85 #include "ardour/recent_sessions.h"
86 #include "ardour/session_directory.h"
87 #include "ardour/session_route.h"
88 #include "ardour/session_state_utils.h"
89 #include "ardour/session_utils.h"
90 #include "ardour/source_factory.h"
91 #include "ardour/slave.h"
92 #include "ardour/system_exec.h"
94 #ifdef WINDOWS_VST_SUPPORT
97 #ifdef AUDIOUNIT_SUPPORT
98 #include "ardour/audio_unit.h"
101 #include "timecode/time.h"
103 typedef uint64_t microseconds_t;
108 #include "add_route_dialog.h"
109 #include "ambiguous_file_dialog.h"
110 #include "ardour_ui.h"
111 #include "audio_clock.h"
112 #include "audio_region_view.h"
113 #include "big_clock_window.h"
114 #include "bundle_manager.h"
115 #include "duplicate_routes_dialog.h"
117 #include "engine_dialog.h"
118 #include "export_video_dialog.h"
119 #include "export_video_infobox.h"
120 #include "gain_meter.h"
121 #include "global_port_matrix.h"
122 #include "gui_object.h"
123 #include "gui_thread.h"
124 #include "keyboard.h"
125 #include "keyeditor.h"
126 #include "location_ui.h"
127 #include "main_clock.h"
128 #include "missing_file_dialog.h"
129 #include "missing_plugin_dialog.h"
130 #include "mixer_ui.h"
131 #include "meterbridge.h"
132 #include "mouse_cursors.h"
135 #include "pingback.h"
136 #include "processor_box.h"
137 #include "prompter.h"
138 #include "public_editor.h"
139 #include "rc_option_editor.h"
140 #include "route_time_axis.h"
141 #include "route_params_ui.h"
142 #include "save_as_dialog.h"
143 #include "session_dialog.h"
144 #include "session_metadata_dialog.h"
145 #include "session_option_editor.h"
146 #include "shuttle_control.h"
147 #include "speaker_dialog.h"
150 #include "theme_manager.h"
151 #include "time_axis_view_item.h"
154 #include "video_server_dialog.h"
155 #include "add_video_dialog.h"
156 #include "transcode_video_dialog.h"
160 using namespace ARDOUR;
161 using namespace ARDOUR_UI_UTILS;
163 using namespace Gtkmm2ext;
166 using namespace Editing;
168 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
170 sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
171 sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
174 ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
176 MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
177 "Would you like these files to be copied and used for %1 %2.x?\n\n"
178 "(This will require you to restart %1.)"),
179 PROGRAM_NAME, PROGRAM_VERSION, version),
180 false, /* no markup */
183 true /* modal, though it hardly matters since it is the only window */
186 msg.set_default_response (Gtk::RESPONSE_YES);
189 return (msg.run() == Gtk::RESPONSE_YES);
193 libxml_generic_error_func (void* /* parsing_context*/,
201 vsnprintf (buf, sizeof (buf), msg, ap);
202 error << buf << endmsg;
207 libxml_structured_error_func (void* /* parsing_context*/,
215 replace_all (msg, "\n", "");
217 if (err->file && err->line) {
218 error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
221 error << ':' << err->int2;
228 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
231 : Gtkmm2ext::UI (PROGRAM_NAME, X_("gui"), argcp, argvp)
233 : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
234 >>>>>>> first compilable version of tabbable design.
235 , session_loaded (false)
236 , gui_object_state (new GUIObjectState)
237 , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
238 , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
239 , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
241 , global_actions (X_("global"))
242 , ignore_dual_punch (false)
247 , _mixer_on_top (false)
248 , _initial_verbose_plugin_scan (false)
249 , first_time_engine_run (true)
250 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
251 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
252 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
253 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
254 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
255 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
256 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
257 , auto_return_button (ArdourButton::led_default_elements)
258 , follow_edits_button (ArdourButton::led_default_elements)
259 , auto_input_button (ArdourButton::led_default_elements)
260 , auditioning_alert_button (_("Audition"))
261 , solo_alert_button (_("Solo"))
262 , feedback_alert_button (_("Feedback"))
263 , error_alert_button ( ArdourButton::just_led_default_elements )
265 , editor_meter_peak_display()
266 , _numpad_locate_happening (false)
267 , _session_is_new (false)
268 , last_key_press_time (0)
271 , rc_option_editor (0)
272 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
273 , add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
274 , about (X_("about"), _("About"))
275 , location_ui (X_("locations"), _("Locations"))
276 , route_params (X_("inspector"), _("Tracks and Busses"))
277 , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
278 , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
279 , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this))
280 , add_video_dialog (X_("add-video"), _("Add Video"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this))
281 , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this))
282 , big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
283 , audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
284 , midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
285 , key_editor (X_("key-editor"), _("Bindings Editor"), boost::bind (&ARDOUR_UI::create_key_editor, this))
286 , video_server_process (0)
288 , have_configure_timeout (false)
289 , last_configure_time (0)
291 , have_disk_speed_dialog_displayed (false)
292 , _status_bar_visibility (X_("status-bar"))
293 , _feedback_exists (false)
294 , _log_not_acknowledged (LogLevelNone)
295 , duplicate_routes_dialog (0)
297 Gtkmm2ext::init (localedir);
299 UIConfiguration::instance().post_gui_init ();
301 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
302 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
304 /* configuration was modified, exit immediately */
308 if (theArdourUI == 0) {
312 /* stop libxml from spewing to stdout/stderr */
314 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
315 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
317 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
318 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
319 UIConfiguration::instance().map_parameters (pc);
321 roll_button.set_controllable (roll_controllable);
322 stop_button.set_controllable (stop_controllable);
323 goto_start_button.set_controllable (goto_start_controllable);
324 goto_end_button.set_controllable (goto_end_controllable);
325 auto_loop_button.set_controllable (auto_loop_controllable);
326 play_selection_button.set_controllable (play_selection_controllable);
327 rec_button.set_controllable (rec_controllable);
329 roll_button.set_name ("transport button");
330 stop_button.set_name ("transport button");
331 goto_start_button.set_name ("transport button");
332 goto_end_button.set_name ("transport button");
333 auto_loop_button.set_name ("transport button");
334 play_selection_button.set_name ("transport button");
335 rec_button.set_name ("transport recenable button");
336 midi_panic_button.set_name ("transport button");
338 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
339 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
341 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
343 /* handle dialog requests */
345 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
347 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
349 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
351 /* handle Audio/MIDI setup when session requires it */
353 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
355 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
357 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
359 /* handle requests to quit (coming from JACK session) */
361 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
363 /* tell the user about feedback */
365 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
366 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
368 /* handle requests to deal with missing files */
370 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
372 /* and ambiguous files */
374 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
376 /* also plugin scan messages */
377 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
378 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
380 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
382 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
385 /* lets get this party started */
387 setup_gtk_ardour_enums ();
390 SessionEvent::create_per_thread_pool ("GUI", 4096);
392 /* we like keyboards */
394 keyboard = new ArdourKeyboard(*this);
396 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
398 keyboard->set_state (*node, Stateful::loading_state_version);
401 /* we don't like certain modifiers */
402 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
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 if (Profile->get_sae()) {
629 primary_clock->set_mode (AudioClock::BBT);
630 secondary_clock->set_mode (AudioClock::MinSec);
632 primary_clock->set_mode (AudioClock::Timecode);
633 secondary_clock->set_mode (AudioClock::BBT);
636 /* start the time-of-day-clock */
639 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
640 update_wall_clock ();
641 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
646 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
647 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
648 Config->map_parameters (pc);
650 UIConfiguration::instance().map_parameters (pc);
654 ARDOUR_UI::~ARDOUR_UI ()
656 UIConfiguration::instance().save_state();
660 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
661 // don't bother at 'real' exit. the OS cleans up for us.
663 delete primary_clock;
664 delete secondary_clock;
665 delete _process_thread;
670 delete gui_object_state;
671 FastMeter::flush_pattern_cache ();
672 PixFader::flush_pattern_cache ();
676 /* Small trick to flush main-thread event pool.
677 * Other thread-pools are destroyed at pthread_exit(),
678 * but tmain thread termination is too late to trigger Pool::~Pool()
680 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.
681 delete ev->event_pool();
686 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
688 if (Splash::instance()) {
689 Splash::instance()->pop_back_for (win);
694 ARDOUR_UI::configure_timeout ()
696 if (last_configure_time == 0) {
697 /* no configure events yet */
701 /* force a gap of 0.5 seconds since the last configure event
704 if (get_microseconds() - last_configure_time < 500000) {
707 have_configure_timeout = false;
708 save_ardour_state ();
714 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
716 if (have_configure_timeout) {
717 last_configure_time = get_microseconds();
719 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
720 have_configure_timeout = true;
727 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
729 const XMLProperty* prop;
731 if ((prop = node.property ("roll")) != 0) {
732 roll_controllable->set_id (prop->value());
734 if ((prop = node.property ("stop")) != 0) {
735 stop_controllable->set_id (prop->value());
737 if ((prop = node.property ("goto-start")) != 0) {
738 goto_start_controllable->set_id (prop->value());
740 if ((prop = node.property ("goto-end")) != 0) {
741 goto_end_controllable->set_id (prop->value());
743 if ((prop = node.property ("auto-loop")) != 0) {
744 auto_loop_controllable->set_id (prop->value());
746 if ((prop = node.property ("play-selection")) != 0) {
747 play_selection_controllable->set_id (prop->value());
749 if ((prop = node.property ("rec")) != 0) {
750 rec_controllable->set_id (prop->value());
752 if ((prop = node.property ("shuttle")) != 0) {
753 shuttle_box->controllable()->set_id (prop->value());
758 ARDOUR_UI::get_transport_controllable_state ()
760 XMLNode* node = new XMLNode(X_("TransportControllables"));
763 roll_controllable->id().print (buf, sizeof (buf));
764 node->add_property (X_("roll"), buf);
765 stop_controllable->id().print (buf, sizeof (buf));
766 node->add_property (X_("stop"), buf);
767 goto_start_controllable->id().print (buf, sizeof (buf));
768 node->add_property (X_("goto_start"), buf);
769 goto_end_controllable->id().print (buf, sizeof (buf));
770 node->add_property (X_("goto_end"), buf);
771 auto_loop_controllable->id().print (buf, sizeof (buf));
772 node->add_property (X_("auto_loop"), buf);
773 play_selection_controllable->id().print (buf, sizeof (buf));
774 node->add_property (X_("play_selection"), buf);
775 rec_controllable->id().print (buf, sizeof (buf));
776 node->add_property (X_("rec"), buf);
777 shuttle_box->controllable()->id().print (buf, sizeof (buf));
778 node->add_property (X_("shuttle"), buf);
784 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
787 _session->save_state (snapshot_name);
792 ARDOUR_UI::autosave_session ()
794 if (g_main_depth() > 1) {
795 /* inside a recursive main loop,
796 give up because we may not be able to
802 if (!Config->get_periodic_safety_backups()) {
807 _session->maybe_write_autosave();
814 ARDOUR_UI::session_dirty_changed ()
821 ARDOUR_UI::update_autosave ()
823 if (_session && _session->dirty()) {
824 if (_autosave_connection.connected()) {
825 _autosave_connection.disconnect();
828 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
829 Config->get_periodic_safety_backup_interval() * 1000);
832 if (_autosave_connection.connected()) {
833 _autosave_connection.disconnect();
839 ARDOUR_UI::check_announcements ()
842 string _annc_filename;
845 _annc_filename = PROGRAM_NAME "_announcements_osx_";
846 #elif defined PLATFORM_WINDOWS
847 _annc_filename = PROGRAM_NAME "_announcements_windows_";
849 _annc_filename = PROGRAM_NAME "_announcements_linux_";
851 _annc_filename.append (VERSIONSTRING);
853 _announce_string = "";
855 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
856 FILE* fin = g_fopen (path.c_str(), "rb");
858 while (!feof (fin)) {
861 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
864 _announce_string.append (tmp, len);
869 pingback (VERSIONSTRING, path);
874 _hide_splash (gpointer arg)
876 ((ARDOUR_UI*)arg)->hide_splash();
881 ARDOUR_UI::starting ()
883 Application* app = Application::instance ();
885 bool brand_new_user = ArdourStartup::required ();
887 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
888 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
890 if (ARDOUR_COMMAND_LINE::check_announcements) {
891 check_announcements ();
896 /* we need to create this early because it may need to set the
897 * audio backend end up.
901 audio_midi_setup.get (true);
903 std::cerr << "audio-midi engine setup failed."<< std::endl;
907 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
908 nsm = new NSM_Client;
909 if (!nsm->init (nsm_url)) {
910 /* the ardour executable may have different names:
912 * waf's obj.target for distro versions: eg ardour4, ardourvst4
913 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
914 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
916 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
918 const char *process_name = g_getenv ("ARDOUR_SELF");
919 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
922 // wait for announce reply from nsm server
923 for ( i = 0; i < 5000; ++i) {
927 if (nsm->is_active()) {
932 error << _("NSM server did not announce itself") << endmsg;
935 // wait for open command from nsm server
936 for ( i = 0; i < 5000; ++i) {
939 if (nsm->client_id ()) {
945 error << _("NSM: no client ID provided") << endmsg;
949 if (_session && nsm) {
950 _session->set_nsm_state( nsm->is_active() );
952 error << _("NSM: no session created") << endmsg;
956 // nsm requires these actions disabled
957 vector<string> action_names;
958 action_names.push_back("SaveAs");
959 action_names.push_back("Rename");
960 action_names.push_back("New");
961 action_names.push_back("Open");
962 action_names.push_back("Recent");
963 action_names.push_back("Close");
965 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
966 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
968 act->set_sensitive (false);
975 error << _("NSM: initialization failed") << endmsg;
981 if (brand_new_user) {
982 _initial_verbose_plugin_scan = true;
987 _initial_verbose_plugin_scan = false;
988 switch (s.response ()) {
989 case Gtk::RESPONSE_OK:
996 #ifdef NO_PLUGIN_STATE
998 ARDOUR::RecentSessions rs;
999 ARDOUR::read_recent_sessions (rs);
1001 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
1003 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
1005 /* already used Ardour, have sessions ... warn about plugin state */
1007 ArdourDialog d (_("Free/Demo Version Warning"), true);
1009 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
1010 CheckButton c (_("Don't warn me about this again"));
1012 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"),
1013 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
1014 _("It will not restore OR save any plugin settings"),
1015 _("If you load an existing session with plugin settings\n"
1016 "they will not be used and will be lost."),
1017 _("To get full access to updates without this limitation\n"
1018 "consider becoming a subscriber for a low cost every month.")));
1019 l.set_justify (JUSTIFY_CENTER);
1021 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1023 d.get_vbox()->pack_start (l, true, true);
1024 d.get_vbox()->pack_start (b, false, false, 12);
1025 d.get_vbox()->pack_start (c, false, false, 12);
1027 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1028 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1032 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1034 if (d.run () != RESPONSE_OK) {
1040 /* go get a session */
1042 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1044 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1045 std::cerr << "Cannot get session parameters."<< std::endl;
1052 WM::Manager::instance().show_visible ();
1054 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1055 * editor window, and we may want stuff to be hidden.
1057 _status_bar_visibility.update ();
1059 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1061 if (splash && splash->is_visible()) {
1062 // in 1 second, hide the splash screen
1063 Glib::signal_timeout().connect (sigc::bind (sigc::ptr_fun (_hide_splash), this), 1000);
1066 /* all other dialogs are created conditionally */
1072 ARDOUR_UI::check_memory_locking ()
1074 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1075 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1079 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1081 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1083 struct rlimit limits;
1085 long pages, page_size;
1087 size_t pages_len=sizeof(pages);
1088 if ((page_size = getpagesize()) < 0 ||
1089 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1091 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1096 ram = (int64_t) pages * (int64_t) page_size;
1099 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1103 if (limits.rlim_cur != RLIM_INFINITY) {
1105 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1109 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1110 "This might cause %1 to run out of memory before your system "
1111 "runs out of memory. \n\n"
1112 "You can view the memory limit with 'ulimit -l', "
1113 "and it is normally controlled by %2"),
1116 X_("/etc/login.conf")
1118 X_(" /etc/security/limits.conf")
1122 msg.set_default_response (RESPONSE_OK);
1124 VBox* vbox = msg.get_vbox();
1126 CheckButton cb (_("Do not show this window again"));
1127 hbox.pack_start (cb, true, false);
1128 vbox->pack_start (hbox);
1133 pop_back_splash (msg);
1137 if (cb.get_active()) {
1138 XMLNode node (X_("no-memory-warning"));
1139 Config->add_instant_xml (node);
1144 #endif // !__APPLE__
1149 ARDOUR_UI::queue_finish ()
1151 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1155 ARDOUR_UI::idle_finish ()
1158 return false; /* do not call again */
1165 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1167 if (_session->dirty()) {
1168 vector<string> actions;
1169 actions.push_back (_("Don't quit"));
1170 actions.push_back (_("Just quit"));
1171 actions.push_back (_("Save and quit"));
1172 switch (ask_about_saving_session(actions)) {
1177 /* use the default name */
1178 if (save_state_canfail ("")) {
1179 /* failed - don't quit */
1180 MessageDialog msg (_main_window,
1181 string_compose (_("\
1182 %1 was unable to save your session.\n\n\
1183 If you still wish to quit, please use the\n\n\
1184 \"Just quit\" option."), PROGRAM_NAME));
1185 pop_back_splash(msg);
1195 second_connection.disconnect ();
1196 point_one_second_connection.disconnect ();
1197 point_zero_something_second_connection.disconnect();
1198 fps_connection.disconnect();
1201 delete ARDOUR_UI::instance()->video_timeline;
1202 ARDOUR_UI::instance()->video_timeline = NULL;
1203 stop_video_server();
1205 /* Save state before deleting the session, as that causes some
1206 windows to be destroyed before their visible state can be
1209 save_ardour_state ();
1211 close_all_dialogs ();
1214 _session->set_clean ();
1215 _session->remove_pending_capture_state ();
1220 halt_connection.disconnect ();
1221 AudioEngine::instance()->stop ();
1222 #ifdef WINDOWS_VST_SUPPORT
1223 fst_stop_threading();
1229 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1231 ArdourDialog window (_("Unsaved Session"));
1232 Gtk::HBox dhbox; // the hbox for the image and text
1233 Gtk::Label prompt_label;
1234 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1238 assert (actions.size() >= 3);
1240 window.add_button (actions[0], RESPONSE_REJECT);
1241 window.add_button (actions[1], RESPONSE_APPLY);
1242 window.add_button (actions[2], RESPONSE_ACCEPT);
1244 window.set_default_response (RESPONSE_ACCEPT);
1246 Gtk::Button noquit_button (msg);
1247 noquit_button.set_name ("EditorGTKButton");
1251 if (_session->snap_name() == _session->name()) {
1252 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?"),
1253 _session->snap_name());
1255 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?"),
1256 _session->snap_name());
1259 prompt_label.set_text (prompt);
1260 prompt_label.set_name (X_("PrompterLabel"));
1261 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1263 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1264 dhbox.set_homogeneous (false);
1265 dhbox.pack_start (*dimage, false, false, 5);
1266 dhbox.pack_start (prompt_label, true, false, 5);
1267 window.get_vbox()->pack_start (dhbox);
1269 window.set_name (_("Prompter"));
1270 window.set_modal (true);
1271 window.set_resizable (false);
1274 prompt_label.show();
1279 ResponseType r = (ResponseType) window.run();
1284 case RESPONSE_ACCEPT: // save and get out of here
1286 case RESPONSE_APPLY: // get out of here
1297 ARDOUR_UI::every_second ()
1300 update_xrun_count ();
1301 update_buffer_load ();
1302 update_disk_space ();
1303 update_timecode_format ();
1304 update_peak_thread_work ();
1306 if (nsm && nsm->is_active ()) {
1309 if (!_was_dirty && _session->dirty ()) {
1313 else if (_was_dirty && !_session->dirty ()){
1321 ARDOUR_UI::every_point_one_seconds ()
1323 // TODO get rid of this..
1324 // ShuttleControl is updated directly via TransportStateChange signal
1328 ARDOUR_UI::every_point_zero_something_seconds ()
1330 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1332 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1333 float mpeak = editor_meter->update_meters();
1334 if (mpeak > editor_meter_max_peak) {
1335 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1336 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1343 ARDOUR_UI::set_fps_timeout_connection ()
1345 unsigned int interval = 40;
1346 if (!_session) return;
1347 if (_session->timecode_frames_per_second() != 0) {
1348 /* ideally we'll use a select() to sleep and not accumulate
1349 * idle time to provide a regular periodic signal.
1350 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1351 * However, that'll require a dedicated thread and cross-thread
1352 * signals to the GUI Thread..
1354 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1355 * _session->frame_rate() / _session->nominal_frame_rate()
1356 / _session->timecode_frames_per_second()
1358 #ifdef PLATFORM_WINDOWS
1359 // the smallest windows scheduler time-slice is ~15ms.
1360 // periodic GUI timeouts shorter than that will cause
1361 // WaitForSingleObject to spinlock (100% of one CPU Core)
1362 // and gtk never enters idle mode.
1363 // also changing timeBeginPeriod(1) does not affect that in
1364 // any beneficial way, so we just limit the max rate for now.
1365 interval = std::max(30u, interval); // at most ~33Hz.
1367 interval = std::max(8u, interval); // at most 120Hz.
1370 fps_connection.disconnect();
1371 Timers::set_fps_interval (interval);
1375 ARDOUR_UI::update_sample_rate (framecnt_t)
1379 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1381 if (!AudioEngine::instance()->connected()) {
1383 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1387 framecnt_t rate = AudioEngine::instance()->sample_rate();
1390 /* no sample rate available */
1391 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1394 if (fmod (rate, 1000.0) != 0.0) {
1395 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1396 (float) rate / 1000.0f,
1397 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1399 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1401 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1405 sample_rate_label.set_markup (buf);
1409 ARDOUR_UI::update_format ()
1412 format_label.set_text ("");
1417 s << _("File:") << X_(" <span foreground=\"green\">");
1419 switch (_session->config.get_native_file_header_format ()) {
1451 switch (_session->config.get_native_file_data_format ()) {
1465 format_label.set_markup (s.str ());
1469 ARDOUR_UI::update_xrun_count ()
1473 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1474 should also be changed.
1478 const unsigned int x = _session->get_xrun_count ();
1480 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1482 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1485 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1487 xrun_label.set_markup (buf);
1488 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1492 ARDOUR_UI::update_cpu_load ()
1496 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1497 should also be changed.
1500 double const c = AudioEngine::instance()->get_dsp_load ();
1501 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1502 cpu_load_label.set_markup (buf);
1506 ARDOUR_UI::update_peak_thread_work ()
1509 const int c = SourceFactory::peak_work_queue_length ();
1511 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1512 peak_thread_work_label.set_markup (buf);
1514 peak_thread_work_label.set_markup (X_(""));
1519 ARDOUR_UI::update_buffer_load ()
1523 uint32_t const playback = _session ? _session->playback_load () : 100;
1524 uint32_t const capture = _session ? _session->capture_load () : 100;
1526 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1527 should also be changed.
1533 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1534 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1535 playback <= 5 ? X_("red") : X_("green"),
1537 capture <= 5 ? X_("red") : X_("green"),
1541 buffer_load_label.set_markup (buf);
1543 buffer_load_label.set_text ("");
1548 ARDOUR_UI::count_recenabled_streams (Route& route)
1550 Track* track = dynamic_cast<Track*>(&route);
1551 if (track && track->record_enabled()) {
1552 rec_enabled_streams += track->n_inputs().n_total();
1557 ARDOUR_UI::update_disk_space()
1559 if (_session == 0) {
1563 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1565 framecnt_t fr = _session->frame_rate();
1568 /* skip update - no SR available */
1573 /* Available space is unknown */
1574 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1575 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1576 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1578 rec_enabled_streams = 0;
1579 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1581 framecnt_t frames = opt_frames.get_value_or (0);
1583 if (rec_enabled_streams) {
1584 frames /= rec_enabled_streams;
1591 hrs = frames / (fr * 3600);
1594 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1596 frames -= hrs * fr * 3600;
1597 mins = frames / (fr * 60);
1598 frames -= mins * fr * 60;
1601 bool const low = (hrs == 0 && mins <= 30);
1605 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1606 low ? X_("red") : X_("green"),
1612 disk_space_label.set_markup (buf);
1616 ARDOUR_UI::update_timecode_format ()
1622 TimecodeSlave* tcslave;
1623 SyncSource sync_src = Config->get_sync_source();
1625 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1626 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1631 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1632 matching ? X_("green") : X_("red"),
1633 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1635 snprintf (buf, sizeof (buf), "TC: n/a");
1638 timecode_format_label.set_markup (buf);
1642 ARDOUR_UI::update_wall_clock ()
1646 static int last_min = -1;
1649 tm_now = localtime (&now);
1650 if (last_min != tm_now->tm_min) {
1652 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1653 wall_clock_label.set_text (buf);
1654 last_min = tm_now->tm_min;
1661 ARDOUR_UI::open_recent_session ()
1663 bool can_return = (_session != 0);
1665 SessionDialog recent_session_dialog;
1669 ResponseType r = (ResponseType) recent_session_dialog.run ();
1672 case RESPONSE_ACCEPT:
1676 recent_session_dialog.hide();
1683 recent_session_dialog.hide();
1687 std::string path = recent_session_dialog.session_folder();
1688 std::string state = recent_session_dialog.session_name (should_be_new);
1690 if (should_be_new == true) {
1694 _session_is_new = false;
1696 if (load_session (path, state) == 0) {
1705 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1707 if (!AudioEngine::instance()->connected()) {
1708 MessageDialog msg (parent, string_compose (
1709 _("%1 is not connected to any audio backend.\n"
1710 "You cannot open or close sessions in this condition"),
1712 pop_back_splash (msg);
1720 ARDOUR_UI::open_session ()
1722 if (!check_audioengine(*editor)) {
1726 /* ardour sessions are folders */
1727 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1728 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1729 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1730 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1733 string session_parent_dir = Glib::path_get_dirname(_session->path());
1734 open_session_selector.set_current_folder(session_parent_dir);
1736 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1739 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1741 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1742 string default_session_folder = Config->get_default_session_parent_dir();
1743 open_session_selector.add_shortcut_folder (default_session_folder);
1745 catch (Glib::Error & e) {
1746 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1749 FileFilter session_filter;
1750 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1751 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1752 open_session_selector.add_filter (session_filter);
1753 open_session_selector.set_filter (session_filter);
1755 int response = open_session_selector.run();
1756 open_session_selector.hide ();
1758 if (response == Gtk::RESPONSE_CANCEL) {
1762 string session_path = open_session_selector.get_filename();
1766 if (session_path.length() > 0) {
1767 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1768 _session_is_new = isnew;
1769 load_session (path, name);
1776 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1777 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1779 list<boost::shared_ptr<MidiTrack> > tracks;
1781 if (_session == 0) {
1782 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1787 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1789 if (tracks.size() != how_many) {
1790 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1795 MessageDialog msg (_main_window,
1796 string_compose (_("There are insufficient ports available\n\
1797 to create a new track or bus.\n\
1798 You should save %1, exit and\n\
1799 restart with more ports."), PROGRAM_NAME));
1806 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1808 ChanCount one_midi_channel;
1809 one_midi_channel.set (DataType::MIDI, 1);
1812 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1817 ARDOUR_UI::session_add_audio_route (
1819 int32_t input_channels,
1820 int32_t output_channels,
1821 ARDOUR::TrackMode mode,
1822 RouteGroup* route_group,
1824 string const & name_template
1827 list<boost::shared_ptr<AudioTrack> > tracks;
1830 if (_session == 0) {
1831 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1837 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1839 if (tracks.size() != how_many) {
1840 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1846 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1848 if (routes.size() != how_many) {
1849 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1856 MessageDialog msg (_main_window,
1857 string_compose (_("There are insufficient ports available\n\
1858 to create a new track or bus.\n\
1859 You should save %1, exit and\n\
1860 restart with more ports."), PROGRAM_NAME));
1861 pop_back_splash (msg);
1867 ARDOUR_UI::transport_goto_start ()
1870 _session->goto_start();
1872 /* force displayed area in editor to start no matter
1873 what "follow playhead" setting is.
1877 editor->center_screen (_session->current_start_frame ());
1883 ARDOUR_UI::transport_goto_zero ()
1886 _session->request_locate (0);
1888 /* force displayed area in editor to start no matter
1889 what "follow playhead" setting is.
1893 editor->reset_x_origin (0);
1899 ARDOUR_UI::transport_goto_wallclock ()
1901 if (_session && editor) {
1908 localtime_r (&now, &tmnow);
1910 framecnt_t frame_rate = _session->frame_rate();
1912 if (frame_rate == 0) {
1913 /* no frame rate available */
1917 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1918 frames += tmnow.tm_min * (60 * frame_rate);
1919 frames += tmnow.tm_sec * frame_rate;
1921 _session->request_locate (frames, _session->transport_rolling ());
1923 /* force displayed area in editor to start no matter
1924 what "follow playhead" setting is.
1928 editor->center_screen (frames);
1934 ARDOUR_UI::transport_goto_end ()
1937 framepos_t const frame = _session->current_end_frame();
1938 _session->request_locate (frame);
1940 /* force displayed area in editor to start no matter
1941 what "follow playhead" setting is.
1945 editor->center_screen (frame);
1951 ARDOUR_UI::transport_stop ()
1957 if (_session->is_auditioning()) {
1958 _session->cancel_audition ();
1962 _session->request_stop (false, true);
1965 /** Check if any tracks are record enabled. If none are, record enable all of them.
1966 * @return true if track record-enabled status was changed, false otherwise.
1969 ARDOUR_UI::trx_record_enable_all_tracks ()
1975 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1976 bool none_record_enabled = true;
1978 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1979 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1982 if (t->record_enabled()) {
1983 none_record_enabled = false;
1988 if (none_record_enabled) {
1989 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1992 return none_record_enabled;
1996 ARDOUR_UI::transport_record (bool roll)
1999 switch (_session->record_status()) {
2000 case Session::Disabled:
2001 if (_session->ntracks() == 0) {
2002 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."));
2006 if (Profile->get_trx()) {
2007 roll = trx_record_enable_all_tracks ();
2009 _session->maybe_enable_record ();
2014 case Session::Recording:
2016 _session->request_stop();
2018 _session->disable_record (false, true);
2022 case Session::Enabled:
2023 _session->disable_record (false, true);
2029 ARDOUR_UI::transport_roll ()
2035 if (_session->is_auditioning()) {
2040 if (_session->config.get_external_sync()) {
2041 switch (Config->get_sync_source()) {
2045 /* transport controlled by the master */
2051 bool rolling = _session->transport_rolling();
2053 if (_session->get_play_loop()) {
2055 /* If loop playback is not a mode, then we should cancel
2056 it when this action is requested. If it is a mode
2057 we just leave it in place.
2060 if (!Config->get_loop_is_mode()) {
2061 /* XXX it is not possible to just leave seamless loop and keep
2062 playing at present (nov 4th 2009)
2064 if (!Config->get_seamless_loop()) {
2065 /* stop loop playback and stop rolling */
2066 _session->request_play_loop (false, true);
2067 } else if (rolling) {
2068 /* stop loop playback but keep rolling */
2069 _session->request_play_loop (false, false);
2073 } else if (_session->get_play_range () ) {
2074 /* stop playing a range if we currently are */
2075 _session->request_play_range (0, true);
2079 _session->request_transport_speed (1.0f);
2084 ARDOUR_UI::get_smart_mode() const
2086 return ( editor->get_smart_mode() );
2091 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2097 if (_session->is_auditioning()) {
2098 _session->cancel_audition ();
2102 if (_session->config.get_external_sync()) {
2103 switch (Config->get_sync_source()) {
2107 /* transport controlled by the master */
2112 bool rolling = _session->transport_rolling();
2113 bool affect_transport = true;
2115 if (rolling && roll_out_of_bounded_mode) {
2116 /* drop out of loop/range playback but leave transport rolling */
2117 if (_session->get_play_loop()) {
2118 if (_session->actively_recording()) {
2120 /* just stop using the loop, then actually stop
2123 _session->request_play_loop (false, affect_transport);
2126 if (Config->get_seamless_loop()) {
2127 /* the disk buffers contain copies of the loop - we can't
2128 just keep playing, so stop the transport. the user
2129 can restart as they wish.
2131 affect_transport = true;
2133 /* disk buffers are normal, so we can keep playing */
2134 affect_transport = false;
2136 _session->request_play_loop (false, affect_transport);
2138 } else if (_session->get_play_range ()) {
2139 affect_transport = false;
2140 _session->request_play_range (0, true);
2144 if (affect_transport) {
2146 _session->request_stop (with_abort, true);
2148 /* the only external sync condition we can be in here
2149 * would be Engine (JACK) sync, in which case we still
2153 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
2154 _session->request_play_range (&editor->get_selection().time, true);
2155 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2157 _session->request_transport_speed (1.0f);
2163 ARDOUR_UI::toggle_session_auto_loop ()
2169 Location * looploc = _session->locations()->auto_loop_location();
2175 if (_session->get_play_loop()) {
2177 /* looping enabled, our job is to disable it */
2179 _session->request_play_loop (false);
2183 /* looping not enabled, our job is to enable it.
2185 loop-is-NOT-mode: this action always starts the transport rolling.
2186 loop-IS-mode: this action simply sets the loop play mechanism, but
2187 does not start transport.
2189 if (Config->get_loop_is_mode()) {
2190 _session->request_play_loop (true, false);
2192 _session->request_play_loop (true, true);
2196 //show the loop markers
2197 looploc->set_hidden (false, this);
2201 ARDOUR_UI::transport_play_selection ()
2207 editor->play_selection ();
2211 ARDOUR_UI::transport_play_preroll ()
2216 editor->play_with_preroll ();
2220 ARDOUR_UI::transport_rewind (int option)
2222 float current_transport_speed;
2225 current_transport_speed = _session->transport_speed();
2227 if (current_transport_speed >= 0.0f) {
2230 _session->request_transport_speed (-1.0f);
2233 _session->request_transport_speed (-4.0f);
2236 _session->request_transport_speed (-0.5f);
2241 _session->request_transport_speed (current_transport_speed * 1.5f);
2247 ARDOUR_UI::transport_forward (int option)
2253 float current_transport_speed = _session->transport_speed();
2255 if (current_transport_speed <= 0.0f) {
2258 _session->request_transport_speed (1.0f);
2261 _session->request_transport_speed (4.0f);
2264 _session->request_transport_speed (0.5f);
2269 _session->request_transport_speed (current_transport_speed * 1.5f);
2274 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2280 boost::shared_ptr<Route> r;
2282 if ((r = _session->route_by_remote_id (rid)) != 0) {
2284 boost::shared_ptr<Track> t;
2286 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2287 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2293 ARDOUR_UI::map_transport_state ()
2296 auto_loop_button.unset_active_state ();
2297 play_selection_button.unset_active_state ();
2298 roll_button.unset_active_state ();
2299 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2303 shuttle_box->map_transport_state ();
2305 float sp = _session->transport_speed();
2311 if (_session->get_play_range()) {
2313 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2314 roll_button.unset_active_state ();
2315 auto_loop_button.unset_active_state ();
2317 } else if (_session->get_play_loop ()) {
2319 auto_loop_button.set_active (true);
2320 play_selection_button.set_active (false);
2321 if (Config->get_loop_is_mode()) {
2322 roll_button.set_active (true);
2324 roll_button.set_active (false);
2329 roll_button.set_active (true);
2330 play_selection_button.set_active (false);
2331 auto_loop_button.set_active (false);
2334 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2335 /* light up both roll and play-selection if they are joined */
2336 roll_button.set_active (true);
2337 play_selection_button.set_active (true);
2340 stop_button.set_active (false);
2344 stop_button.set_active (true);
2345 roll_button.set_active (false);
2346 play_selection_button.set_active (false);
2347 if (Config->get_loop_is_mode ()) {
2348 auto_loop_button.set_active (_session->get_play_loop());
2350 auto_loop_button.set_active (false);
2352 update_disk_space ();
2357 ARDOUR_UI::blink_handler (bool blink_on)
2359 transport_rec_enable_blink (blink_on);
2360 solo_blink (blink_on);
2361 sync_blink (blink_on);
2362 audition_blink (blink_on);
2363 feedback_blink (blink_on);
2364 error_blink (blink_on);
2368 ARDOUR_UI::update_clocks ()
2370 if (!_session) return;
2372 if (editor && !editor->dragging_playhead()) {
2373 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2378 ARDOUR_UI::start_clocking ()
2380 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2381 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2383 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2388 ARDOUR_UI::stop_clocking ()
2390 clock_signal_connection.disconnect ();
2394 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2398 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2400 label->set_text (buf);
2401 bar->set_fraction (fraction);
2403 /* process events, redraws, etc. */
2405 while (gtk_events_pending()) {
2406 gtk_main_iteration ();
2409 return true; /* continue with save-as */
2413 ARDOUR_UI::save_session_as ()
2419 if (!save_as_dialog) {
2420 save_as_dialog = new SaveAsDialog;
2423 save_as_dialog->set_name (_session->name());
2425 int response = save_as_dialog->run ();
2427 save_as_dialog->hide ();
2430 case Gtk::RESPONSE_OK:
2439 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2440 sa.new_name = save_as_dialog->new_name ();
2441 sa.switch_to = save_as_dialog->switch_to();
2442 sa.copy_media = save_as_dialog->copy_media();
2443 sa.copy_external = save_as_dialog->copy_external();
2444 sa.include_media = save_as_dialog->include_media ();
2446 /* Only bother with a progress dialog if we're going to copy
2447 media into the save-as target. Without that choice, this
2448 will be very fast because we're only talking about a few kB's to
2449 perhaps a couple of MB's of data.
2452 ArdourDialog progress_dialog (_("Save As"), true);
2454 if (sa.include_media && sa.copy_media) {
2457 Gtk::ProgressBar progress_bar;
2459 progress_dialog.get_vbox()->pack_start (label);
2460 progress_dialog.get_vbox()->pack_start (progress_bar);
2462 progress_bar.show ();
2464 /* this signal will be emitted from within this, the calling thread,
2465 * after every file is copied. It provides information on percentage
2466 * complete (in terms of total data to copy), the number of files
2467 * copied so far, and the total number to copy.
2472 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2474 progress_dialog.show_all ();
2475 progress_dialog.present ();
2478 if (_session->save_as (sa)) {
2480 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2484 if (!sa.include_media) {
2485 unload_session (false);
2486 load_session (sa.final_session_folder_name, sa.new_name);
2491 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2495 struct tm local_time;
2498 localtime_r (&n, &local_time);
2499 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2501 save_state (timebuf, switch_to_it);
2506 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2510 prompter.get_result (snapname);
2512 bool do_save = (snapname.length() != 0);
2515 char illegal = Session::session_name_is_legal(snapname);
2517 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2518 "snapshot names may not contain a '%1' character"), illegal));
2524 vector<std::string> p;
2525 get_state_files_in_directory (_session->session_directory().root_path(), p);
2526 vector<string> n = get_file_names_no_extension (p);
2528 if (find (n.begin(), n.end(), snapname) != n.end()) {
2530 do_save = overwrite_file_dialog (prompter,
2531 _("Confirm Snapshot Overwrite"),
2532 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2536 save_state (snapname, switch_to_it);
2546 /** Ask the user for the name of a new snapshot and then take it.
2550 ARDOUR_UI::snapshot_session (bool switch_to_it)
2552 ArdourPrompter prompter (true);
2554 prompter.set_name ("Prompter");
2555 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2557 prompter.set_title (_("Save as..."));
2558 prompter.set_prompt (_("New session name"));
2560 prompter.set_title (_("Take Snapshot"));
2561 prompter.set_prompt (_("Name of new snapshot"));
2565 prompter.set_initial_text (_session->snap_name());
2569 struct tm local_time;
2572 localtime_r (&n, &local_time);
2573 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2574 prompter.set_initial_text (timebuf);
2577 bool finished = false;
2579 switch (prompter.run()) {
2580 case RESPONSE_ACCEPT:
2582 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2593 /** Ask the user for a new session name and then rename the session to it.
2597 ARDOUR_UI::rename_session ()
2603 ArdourPrompter prompter (true);
2606 prompter.set_name ("Prompter");
2607 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2608 prompter.set_title (_("Rename Session"));
2609 prompter.set_prompt (_("New session name"));
2612 switch (prompter.run()) {
2613 case RESPONSE_ACCEPT:
2615 prompter.get_result (name);
2617 bool do_rename = (name.length() != 0);
2620 char illegal = Session::session_name_is_legal (name);
2623 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2624 "session names may not contain a '%1' character"), illegal));
2629 switch (_session->rename (name)) {
2631 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2632 msg.set_position (WIN_POS_MOUSE);
2640 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2641 msg.set_position (WIN_POS_MOUSE);
2657 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2659 if (!_session || _session->deletion_in_progress()) {
2663 XMLNode* node = new XMLNode (X_("UI"));
2665 WM::Manager::instance().add_state (*node);
2667 node->add_child_nocopy (gui_object_state->get_state());
2669 _session->add_extra_xml (*node);
2671 if (export_video_dialog) {
2672 _session->add_extra_xml (export_video_dialog->get_state());
2675 save_state_canfail (name, switch_to_it);
2679 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2684 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2689 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2694 ARDOUR_UI::primary_clock_value_changed ()
2697 _session->request_locate (primary_clock->current_time ());
2702 ARDOUR_UI::big_clock_value_changed ()
2705 _session->request_locate (big_clock->current_time ());
2710 ARDOUR_UI::secondary_clock_value_changed ()
2713 _session->request_locate (secondary_clock->current_time ());
2718 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2720 if (_session == 0) {
2724 if (_session->step_editing()) {
2728 Session::RecordState const r = _session->record_status ();
2729 bool const h = _session->have_rec_enabled_track ();
2731 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2733 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2735 rec_button.set_active_state (Gtkmm2ext::Off);
2737 } else if (r == Session::Recording && h) {
2738 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2740 rec_button.unset_active_state ();
2745 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2749 prompter.get_result (name);
2751 if (name.length()) {
2752 int failed = _session->save_template (name);
2754 if (failed == -2) { /* file already exists. */
2755 bool overwrite = overwrite_file_dialog (prompter,
2756 _("Confirm Template Overwrite"),
2757 _("A template already exists with that name. Do you want to overwrite it?"));
2760 _session->save_template (name, true);
2772 ARDOUR_UI::save_template ()
2774 ArdourPrompter prompter (true);
2776 if (!check_audioengine(*editor)) {
2780 prompter.set_name (X_("Prompter"));
2781 prompter.set_title (_("Save Template"));
2782 prompter.set_prompt (_("Name for template:"));
2783 prompter.set_initial_text(_session->name() + _("-template"));
2784 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2786 bool finished = false;
2788 switch (prompter.run()) {
2789 case RESPONSE_ACCEPT:
2790 finished = process_save_template_prompter (prompter);
2801 ARDOUR_UI::edit_metadata ()
2803 SessionMetadataEditor dialog;
2804 dialog.set_session (_session);
2805 dialog.grab_focus ();
2810 ARDOUR_UI::import_metadata ()
2812 SessionMetadataImporter dialog;
2813 dialog.set_session (_session);
2818 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2820 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2822 MessageDialog msg (str,
2824 Gtk::MESSAGE_WARNING,
2825 Gtk::BUTTONS_YES_NO,
2829 msg.set_name (X_("OpenExistingDialog"));
2830 msg.set_title (_("Open Existing Session"));
2831 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2832 msg.set_position (Gtk::WIN_POS_CENTER);
2833 pop_back_splash (msg);
2835 switch (msg.run()) {
2844 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2846 BusProfile bus_profile;
2848 if (nsm || Profile->get_sae()) {
2850 bus_profile.master_out_channels = 2;
2851 bus_profile.input_ac = AutoConnectPhysical;
2852 bus_profile.output_ac = AutoConnectMaster;
2853 bus_profile.requested_physical_in = 0; // use all available
2854 bus_profile.requested_physical_out = 0; // use all available
2858 /* get settings from advanced section of NSD */
2860 if (sd.create_master_bus()) {
2861 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2863 bus_profile.master_out_channels = 0;
2866 if (sd.connect_inputs()) {
2867 bus_profile.input_ac = AutoConnectPhysical;
2869 bus_profile.input_ac = AutoConnectOption (0);
2872 bus_profile.output_ac = AutoConnectOption (0);
2874 if (sd.connect_outputs ()) {
2875 if (sd.connect_outs_to_master()) {
2876 bus_profile.output_ac = AutoConnectMaster;
2877 } else if (sd.connect_outs_to_physical()) {
2878 bus_profile.output_ac = AutoConnectPhysical;
2882 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2883 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2886 if (build_session (session_path, session_name, bus_profile)) {
2894 ARDOUR_UI::load_from_application_api (const std::string& path)
2896 ARDOUR_COMMAND_LINE::session_name = path;
2897 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2899 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2901 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2902 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2903 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2904 * -> SessionDialog is not displayed
2907 if (_session_dialog) {
2908 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2909 std::string session_path = path;
2910 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2911 session_path = Glib::path_get_dirname (session_path);
2913 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2914 _session_dialog->set_provided_session (session_name, session_path);
2915 _session_dialog->response (RESPONSE_NONE);
2916 _session_dialog->hide();
2921 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2922 /* /path/to/foo => /path/to/foo, foo */
2923 rv = load_session (path, basename_nosuffix (path));
2925 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2926 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2929 // if load_session fails -> pop up SessionDialog.
2931 ARDOUR_COMMAND_LINE::session_name = "";
2933 if (get_session_parameters (true, false)) {
2937 goto_editor_window ();
2941 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2943 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2945 string session_name;
2946 string session_path;
2947 string template_name;
2949 bool likely_new = false;
2950 bool cancel_not_quit;
2952 /* deal with any existing DIRTY session now, rather than later. don't
2953 * treat a non-dirty session this way, so that it stays visible
2954 * as we bring up the new session dialog.
2957 if (_session && ARDOUR_UI::instance()->video_timeline) {
2958 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2961 /* if there is already a session, relabel the button
2962 on the SessionDialog so that we don't Quit directly
2964 cancel_not_quit = (_session != 0);
2966 if (_session && _session->dirty()) {
2967 if (unload_session (false)) {
2968 /* unload cancelled by user */
2971 ARDOUR_COMMAND_LINE::session_name = "";
2974 if (!load_template.empty()) {
2975 should_be_new = true;
2976 template_name = load_template;
2979 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2980 session_path = ARDOUR_COMMAND_LINE::session_name;
2982 if (!session_path.empty()) {
2983 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2984 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2985 /* session/snapshot file, change path to be dir */
2986 session_path = Glib::path_get_dirname (session_path);
2991 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2993 _session_dialog = &session_dialog;
2996 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2998 /* if they named a specific statefile, use it, otherwise they are
2999 just giving a session folder, and we want to use it as is
3000 to find the session.
3003 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
3005 if (suffix != string::npos) {
3006 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
3007 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
3008 session_name = Glib::path_get_basename (session_name);
3010 session_path = ARDOUR_COMMAND_LINE::session_name;
3011 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
3016 session_dialog.clear_given ();
3019 if (should_be_new || session_name.empty()) {
3020 /* need the dialog to get info from user */
3022 cerr << "run dialog\n";
3024 switch (session_dialog.run()) {
3025 case RESPONSE_ACCEPT:
3028 /* this is used for async * app->ShouldLoad(). */
3029 continue; // while loop
3032 if (quit_on_cancel) {
3033 // JE - Currently (July 2014) this section can only get reached if the
3034 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3035 // point does NOT indicate an abnormal termination). Therefore, let's
3036 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3038 pthread_cancel_all ();
3046 session_dialog.hide ();
3049 /* if we run the startup dialog again, offer more than just "new session" */
3051 should_be_new = false;
3053 session_name = session_dialog.session_name (likely_new);
3054 session_path = session_dialog.session_folder ();
3060 string::size_type suffix = session_name.find (statefile_suffix);
3062 if (suffix != string::npos) {
3063 session_name = session_name.substr (0, suffix);
3066 /* this shouldn't happen, but we catch it just in case it does */
3068 if (session_name.empty()) {
3072 if (session_dialog.use_session_template()) {
3073 template_name = session_dialog.session_template_name();
3074 _session_is_new = true;
3077 if (session_name[0] == G_DIR_SEPARATOR ||
3078 #ifdef PLATFORM_WINDOWS
3079 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3081 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3082 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3087 /* absolute path or cwd-relative path specified for session name: infer session folder
3088 from what was given.
3091 session_path = Glib::path_get_dirname (session_name);
3092 session_name = Glib::path_get_basename (session_name);
3096 session_path = session_dialog.session_folder();
3098 char illegal = Session::session_name_is_legal (session_name);
3101 MessageDialog msg (session_dialog,
3102 string_compose (_("To ensure compatibility with various systems\n"
3103 "session names may not contain a '%1' character"),
3106 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3111 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3114 if (likely_new && !nsm) {
3116 std::string existing = Glib::build_filename (session_path, session_name);
3118 if (!ask_about_loading_existing_session (existing)) {
3119 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3124 _session_is_new = false;
3129 pop_back_splash (session_dialog);
3130 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3132 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3136 char illegal = Session::session_name_is_legal(session_name);
3139 pop_back_splash (session_dialog);
3140 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3141 "session names may not contain a '%1' character"), illegal));
3143 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3147 _session_is_new = true;
3150 if (likely_new && template_name.empty()) {
3152 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3156 ret = load_session (session_path, session_name, template_name);
3159 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3163 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3164 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3168 /* clear this to avoid endless attempts to load the
3172 ARDOUR_COMMAND_LINE::session_name = "";
3176 _session_dialog = NULL;
3182 ARDOUR_UI::close_session()
3184 if (!check_audioengine(*editor)) {
3188 if (unload_session (true)) {
3192 ARDOUR_COMMAND_LINE::session_name = "";
3194 if (get_session_parameters (true, false)) {
3199 /** @param snap_name Snapshot name (without .ardour suffix).
3200 * @return -2 if the load failed because we are not connected to the AudioEngine.
3203 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3205 Session *new_session;
3210 unload_status = unload_session ();
3212 if (unload_status < 0) {
3214 } else if (unload_status > 0) {
3220 session_loaded = false;
3222 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3225 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3228 /* this one is special */
3230 catch (AudioEngine::PortRegistrationFailure& err) {
3232 MessageDialog msg (err.what(),
3235 Gtk::BUTTONS_CLOSE);
3237 msg.set_title (_("Port Registration Error"));
3238 msg.set_secondary_text (_("Click the Close button to try again."));
3239 msg.set_position (Gtk::WIN_POS_CENTER);
3240 pop_back_splash (msg);
3243 int response = msg.run ();
3248 case RESPONSE_CANCEL:
3255 catch (SessionException e) {
3256 MessageDialog msg (string_compose(
3257 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3258 path, snap_name, e.what()),
3263 msg.set_title (_("Loading Error"));
3264 msg.set_position (Gtk::WIN_POS_CENTER);
3265 pop_back_splash (msg);
3277 MessageDialog msg (string_compose(
3278 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3284 msg.set_title (_("Loading Error"));
3285 msg.set_position (Gtk::WIN_POS_CENTER);
3286 pop_back_splash (msg);
3298 list<string> const u = new_session->unknown_processors ();
3300 MissingPluginDialog d (_session, u);
3305 if (!new_session->writable()) {
3306 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3311 msg.set_title (_("Read-only Session"));
3312 msg.set_position (Gtk::WIN_POS_CENTER);
3313 pop_back_splash (msg);
3320 /* Now the session been created, add the transport controls */
3321 new_session->add_controllable(roll_controllable);
3322 new_session->add_controllable(stop_controllable);
3323 new_session->add_controllable(goto_start_controllable);
3324 new_session->add_controllable(goto_end_controllable);
3325 new_session->add_controllable(auto_loop_controllable);
3326 new_session->add_controllable(play_selection_controllable);
3327 new_session->add_controllable(rec_controllable);
3329 set_session (new_session);
3331 session_loaded = true;
3334 _session->set_clean ();
3337 #ifdef WINDOWS_VST_SUPPORT
3338 fst_stop_threading();
3342 Timers::TimerSuspender t;
3346 #ifdef WINDOWS_VST_SUPPORT
3347 fst_start_threading();
3356 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3358 Session *new_session;
3361 session_loaded = false;
3362 x = unload_session ();
3370 _session_is_new = true;
3373 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3376 catch (SessionException e) {
3378 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3379 msg.set_title (_("Loading Error"));
3380 msg.set_position (Gtk::WIN_POS_CENTER);
3381 pop_back_splash (msg);
3387 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3388 msg.set_title (_("Loading Error"));
3389 msg.set_position (Gtk::WIN_POS_CENTER);
3390 pop_back_splash (msg);
3395 /* Give the new session the default GUI state, if such things exist */
3398 n = Config->instant_xml (X_("Editor"));
3400 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3401 new_session->add_instant_xml (*n, false);
3403 n = Config->instant_xml (X_("Mixer"));
3405 new_session->add_instant_xml (*n, false);
3408 /* Put the playhead at 0 and scroll fully left */
3409 n = new_session->instant_xml (X_("Editor"));
3411 n->add_property (X_("playhead"), X_("0"));
3412 n->add_property (X_("left-frame"), X_("0"));
3415 set_session (new_session);
3417 session_loaded = true;
3419 new_session->save_state(new_session->name());
3425 ARDOUR_UI::launch_chat ()
3427 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3429 dialog.set_title (_("About the Chat"));
3430 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."));
3432 switch (dialog.run()) {
3435 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3436 #elif defined PLATFORM_WINDOWS
3437 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3439 open_uri("http://webchat.freenode.net/?channels=ardour");
3448 ARDOUR_UI::launch_manual ()
3450 PBD::open_uri (Config->get_tutorial_manual_url());
3454 ARDOUR_UI::launch_reference ()
3456 PBD::open_uri (Config->get_reference_manual_url());
3460 ARDOUR_UI::launch_tracker ()
3462 PBD::open_uri ("http://tracker.ardour.org");
3466 ARDOUR_UI::launch_subscribe ()
3468 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3472 ARDOUR_UI::launch_cheat_sheet ()
3475 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3477 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3482 ARDOUR_UI::launch_website ()
3484 PBD::open_uri ("http://ardour.org");
3488 ARDOUR_UI::launch_website_dev ()
3490 PBD::open_uri ("http://ardour.org/development.html");
3494 ARDOUR_UI::launch_forums ()
3496 PBD::open_uri ("https://community.ardour.org/forums");
3500 ARDOUR_UI::launch_howto_report ()
3502 PBD::open_uri ("http://ardour.org/reporting_bugs");
3506 ARDOUR_UI::loading_message (const std::string& msg)
3508 if (ARDOUR_COMMAND_LINE::no_splash) {
3516 splash->message (msg);
3520 ARDOUR_UI::show_splash ()
3524 splash = new Splash;
3534 ARDOUR_UI::hide_splash ()
3541 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3545 removed = rep.paths.size();
3548 MessageDialog msgd (_main_window,
3549 _("No files were ready for clean-up"),
3553 msgd.set_title (_("Clean-up"));
3554 msgd.set_secondary_text (_("If this seems suprising, \n\
3555 check for any existing snapshots.\n\
3556 These may still include regions that\n\
3557 require some unused files to continue to exist."));
3563 ArdourDialog results (_("Clean-up"), true, false);
3565 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3566 CleanupResultsModelColumns() {
3570 Gtk::TreeModelColumn<std::string> visible_name;
3571 Gtk::TreeModelColumn<std::string> fullpath;
3575 CleanupResultsModelColumns results_columns;
3576 Glib::RefPtr<Gtk::ListStore> results_model;
3577 Gtk::TreeView results_display;
3579 results_model = ListStore::create (results_columns);
3580 results_display.set_model (results_model);
3581 results_display.append_column (list_title, results_columns.visible_name);
3583 results_display.set_name ("CleanupResultsList");
3584 results_display.set_headers_visible (true);
3585 results_display.set_headers_clickable (false);
3586 results_display.set_reorderable (false);
3588 Gtk::ScrolledWindow list_scroller;
3591 Gtk::HBox dhbox; // the hbox for the image and text
3592 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3593 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3595 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3597 const string dead_directory = _session->session_directory().dead_path();
3600 %1 - number of files removed
3601 %2 - location of "dead"
3602 %3 - size of files affected
3603 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3606 const char* bprefix;
3607 double space_adjusted = 0;
3609 if (rep.space < 1000) {
3611 space_adjusted = rep.space;
3612 } else if (rep.space < 1000000) {
3613 bprefix = _("kilo");
3614 space_adjusted = floorf((float)rep.space / 1000.0);
3615 } else if (rep.space < 1000000 * 1000) {
3616 bprefix = _("mega");
3617 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3619 bprefix = _("giga");
3620 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3624 txt.set_markup (string_compose (P_("\
3625 The following file was deleted from %2,\n\
3626 releasing %3 %4bytes of disk space", "\
3627 The following %1 files were deleted from %2,\n\
3628 releasing %3 %4bytes of disk space", removed),
3629 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3631 txt.set_markup (string_compose (P_("\
3632 The following file was not in use and \n\
3633 has 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", "\
3637 The following %1 files were not in use and \n\
3638 have been moved to: %2\n\n\
3639 After a restart of %5\n\n\
3640 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3641 will release an additional %3 %4bytes of disk space.\n", removed),
3642 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3645 dhbox.pack_start (*dimage, true, false, 5);
3646 dhbox.pack_start (txt, true, false, 5);
3648 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3649 TreeModel::Row row = *(results_model->append());
3650 row[results_columns.visible_name] = *i;
3651 row[results_columns.fullpath] = *i;
3654 list_scroller.add (results_display);
3655 list_scroller.set_size_request (-1, 150);
3656 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3658 dvbox.pack_start (dhbox, true, false, 5);
3659 dvbox.pack_start (list_scroller, true, false, 5);
3660 ddhbox.pack_start (dvbox, true, false, 5);
3662 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3663 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3664 results.set_default_response (RESPONSE_CLOSE);
3665 results.set_position (Gtk::WIN_POS_MOUSE);
3667 results_display.show();
3668 list_scroller.show();
3675 //results.get_vbox()->show();
3676 results.set_resizable (false);
3683 ARDOUR_UI::cleanup ()
3685 if (_session == 0) {
3686 /* shouldn't happen: menu item is insensitive */
3691 MessageDialog checker (_("Are you sure you want to clean-up?"),
3693 Gtk::MESSAGE_QUESTION,
3696 checker.set_title (_("Clean-up"));
3698 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3699 ALL undo/redo information will be lost if you clean-up.\n\
3700 Clean-up will move all unused files to a \"dead\" location."));
3702 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3703 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3704 checker.set_default_response (RESPONSE_CANCEL);
3706 checker.set_name (_("CleanupDialog"));
3707 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3708 checker.set_position (Gtk::WIN_POS_MOUSE);
3710 switch (checker.run()) {
3711 case RESPONSE_ACCEPT:
3717 ARDOUR::CleanupReport rep;
3719 editor->prepare_for_cleanup ();
3721 /* do not allow flush until a session is reloaded */
3723 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3725 act->set_sensitive (false);
3728 if (_session->cleanup_sources (rep)) {
3729 editor->finish_cleanup ();
3733 editor->finish_cleanup ();
3736 display_cleanup_results (rep, _("Cleaned Files"), false);
3740 ARDOUR_UI::flush_trash ()
3742 if (_session == 0) {
3743 /* shouldn't happen: menu item is insensitive */
3747 ARDOUR::CleanupReport rep;
3749 if (_session->cleanup_trash_sources (rep)) {
3753 display_cleanup_results (rep, _("deleted file"), true);
3757 ARDOUR_UI::cleanup_peakfiles ()
3759 if (_session == 0) {
3760 /* shouldn't happen: menu item is insensitive */
3764 if (! _session->can_cleanup_peakfiles ()) {
3768 // get all region-views in this session
3770 TrackViewList empty;
3772 editor->get_regions_after(rs, (framepos_t) 0, empty);
3773 std::list<RegionView*> views = rs.by_layer();
3775 // remove displayed audio-region-views waveforms
3776 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3777 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3778 if (!arv) { continue ; }
3779 arv->delete_waves();
3782 // cleanup peak files:
3783 // - stop pending peakfile threads
3784 // - close peakfiles if any
3785 // - remove peak dir in session
3786 // - setup peakfiles (background thread)
3787 _session->cleanup_peakfiles ();
3789 // re-add waves to ARV
3790 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3791 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3792 if (!arv) { continue ; }
3793 arv->create_waves();
3798 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3800 uint32_t order_hint = UINT32_MAX;
3802 if (editor->get_selection().tracks.empty()) {
3807 we want the new routes to have their order keys set starting from
3808 the highest order key in the selection + 1 (if available).
3811 if (place == AddRouteDialog::AfterSelection) {
3812 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3814 order_hint = rtav->route()->order_key();
3817 } else if (place == AddRouteDialog::BeforeSelection) {
3818 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3820 order_hint = rtav->route()->order_key();
3822 } else if (place == AddRouteDialog::First) {
3825 /* leave order_hint at UINT32_MAX */
3828 if (order_hint == UINT32_MAX) {
3829 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3830 * not setting an order hint will place new routes last.
3835 _session->set_order_hint (order_hint);
3837 /* create a gap in the existing route order keys to accomodate new routes.*/
3838 boost::shared_ptr <RouteList> rd = _session->get_routes();
3839 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3840 boost::shared_ptr<Route> rt (*ri);
3842 if (rt->is_monitor()) {
3846 if (rt->order_key () >= order_hint) {
3847 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3853 ARDOUR_UI::start_duplicate_routes ()
3855 if (!duplicate_routes_dialog) {
3856 duplicate_routes_dialog = new DuplicateRouteDialog;
3859 if (duplicate_routes_dialog->restart (_session)) {
3863 duplicate_routes_dialog->present ();
3867 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3875 if (add_route_dialog->is_visible()) {
3876 /* we're already doing this */
3880 ResponseType r = (ResponseType) add_route_dialog->run ();
3882 add_route_dialog->hide();
3885 case RESPONSE_ACCEPT:
3892 if ((count = add_route_dialog->count()) <= 0) {
3896 setup_order_hint(add_route_dialog->insert_at());
3898 string template_path = add_route_dialog->track_template();
3899 DisplaySuspender ds;
3901 if (!template_path.empty()) {
3902 if (add_route_dialog->name_template_is_default()) {
3903 _session->new_route_from_template (count, template_path, string());
3905 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3910 ChanCount input_chan= add_route_dialog->channels ();
3911 ChanCount output_chan;
3912 string name_template = add_route_dialog->name_template ();
3913 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3914 RouteGroup* route_group = add_route_dialog->route_group ();
3915 AutoConnectOption oac = Config->get_output_auto_connect();
3917 if (oac & AutoConnectMaster) {
3918 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3919 output_chan.set (DataType::MIDI, 0);
3921 output_chan = input_chan;
3924 /* XXX do something with name template */
3926 switch (add_route_dialog->type_wanted()) {
3927 case AddRouteDialog::AudioTrack:
3928 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3930 case AddRouteDialog::MidiTrack:
3931 session_add_midi_track (route_group, count, name_template, instrument);
3933 case AddRouteDialog::MixedTrack:
3934 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3936 case AddRouteDialog::AudioBus:
3937 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3943 ARDOUR_UI::stop_video_server (bool ask_confirm)
3945 if (!video_server_process && ask_confirm) {
3946 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3948 if (video_server_process) {
3950 ArdourDialog confirm (_("Stop Video-Server"), true);
3951 Label m (_("Do you really want to stop the Video Server?"));
3952 confirm.get_vbox()->pack_start (m, true, true);
3953 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3954 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3955 confirm.show_all ();
3956 if (confirm.run() == RESPONSE_CANCEL) {
3960 delete video_server_process;
3961 video_server_process =0;
3966 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3968 ARDOUR_UI::start_video_server( float_window, true);
3972 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3978 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3979 if (video_server_process) {
3980 popup_error(_("The Video Server is already started."));
3982 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3988 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3990 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3992 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3994 video_server_dialog->set_transient_for (*float_window);
3997 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3998 video_server_dialog->hide();
4000 ResponseType r = (ResponseType) video_server_dialog->run ();
4001 video_server_dialog->hide();
4002 if (r != RESPONSE_ACCEPT) { return false; }
4003 if (video_server_dialog->show_again()) {
4004 Config->set_show_video_server_dialog(false);
4008 std::string icsd_exec = video_server_dialog->get_exec_path();
4009 std::string icsd_docroot = video_server_dialog->get_docroot();
4010 if (icsd_docroot.empty()) {
4011 #ifndef PLATFORM_WINDOWS
4012 icsd_docroot = X_("/");
4014 icsd_docroot = X_("C:\\");
4019 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
4020 warning << _("Specified docroot is not an existing directory.") << endmsg;
4023 #ifndef PLATFORM_WINDOWS
4024 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4025 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4026 warning << _("Given Video Server is not an executable file.") << endmsg;
4030 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4031 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4032 warning << _("Given Video Server is not an executable file.") << endmsg;
4038 argp=(char**) calloc(9,sizeof(char*));
4039 argp[0] = strdup(icsd_exec.c_str());
4040 argp[1] = strdup("-P");
4041 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4042 argp[3] = strdup("-p");
4043 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4044 argp[5] = strdup("-C");
4045 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4046 argp[7] = strdup(icsd_docroot.c_str());
4048 stop_video_server();
4050 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4051 Config->set_video_advanced_setup(false);
4053 std::ostringstream osstream;
4054 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4055 Config->set_video_server_url(osstream.str());
4056 Config->set_video_server_docroot(icsd_docroot);
4057 Config->set_video_advanced_setup(true);
4060 if (video_server_process) {
4061 delete video_server_process;
4064 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4065 if (video_server_process->start()) {
4066 warning << _("Cannot launch the video-server") << endmsg;
4069 int timeout = 120; // 6 sec
4070 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4071 Glib::usleep (50000);
4073 if (--timeout <= 0 || !video_server_process->is_running()) break;
4076 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4078 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4079 delete video_server_process;
4080 video_server_process = 0;
4088 ARDOUR_UI::add_video (Gtk::Window* float_window)
4094 if (!start_video_server(float_window, false)) {
4095 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4100 add_video_dialog->set_transient_for (*float_window);
4103 if (add_video_dialog->is_visible()) {
4104 /* we're already doing this */
4108 ResponseType r = (ResponseType) add_video_dialog->run ();
4109 add_video_dialog->hide();
4110 if (r != RESPONSE_ACCEPT) { return; }
4112 bool local_file, orig_local_file;
4113 std::string path = add_video_dialog->file_name(local_file);
4115 std::string orig_path = path;
4116 orig_local_file = local_file;
4118 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4120 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4121 warning << string_compose(_("could not open %1"), path) << endmsg;
4124 if (!local_file && path.length() == 0) {
4125 warning << _("no video-file selected") << endmsg;
4129 std::string audio_from_video;
4130 bool detect_ltc = false;
4132 switch (add_video_dialog->import_option()) {
4133 case VTL_IMPORT_TRANSCODE:
4135 TranscodeVideoDialog *transcode_video_dialog;
4136 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4137 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4138 transcode_video_dialog->hide();
4139 if (r != RESPONSE_ACCEPT) {
4140 delete transcode_video_dialog;
4144 audio_from_video = transcode_video_dialog->get_audiofile();
4146 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4149 else if (!audio_from_video.empty()) {
4150 editor->embed_audio_from_video(
4152 video_timeline->get_offset(),
4153 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4156 switch (transcode_video_dialog->import_option()) {
4157 case VTL_IMPORT_TRANSCODED:
4158 path = transcode_video_dialog->get_filename();
4161 case VTL_IMPORT_REFERENCE:
4164 delete transcode_video_dialog;
4167 delete transcode_video_dialog;
4171 case VTL_IMPORT_NONE:
4175 /* strip _session->session_directory().video_path() from video file if possible */
4176 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4177 path=path.substr(_session->session_directory().video_path().size());
4178 if (path.at(0) == G_DIR_SEPARATOR) {
4179 path=path.substr(1);
4183 video_timeline->set_update_session_fps(auto_set_session_fps);
4185 if (video_timeline->video_file_info(path, local_file)) {
4186 XMLNode* node = new XMLNode(X_("Videotimeline"));
4187 node->add_property (X_("Filename"), path);
4188 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4189 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4190 if (orig_local_file) {
4191 node->add_property (X_("OriginalVideoFile"), orig_path);
4193 node->remove_property (X_("OriginalVideoFile"));
4195 _session->add_extra_xml (*node);
4196 _session->set_dirty ();
4198 if (!audio_from_video.empty() && detect_ltc) {
4199 std::vector<LTCFileReader::LTCMap> ltc_seq;
4202 /* TODO ask user about TV standard (LTC alignment if any) */
4203 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4204 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4206 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4208 /* TODO seek near end of file, and read LTC until end.
4209 * if it fails to find any LTC frames, scan complete file
4211 * calculate drift of LTC compared to video-duration,
4212 * ask user for reference (timecode from start/mid/end)
4215 // LTCFileReader will have written error messages
4218 ::g_unlink(audio_from_video.c_str());
4220 if (ltc_seq.size() == 0) {
4221 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4223 /* the very first TC in the file is somteimes not aligned properly */
4224 int i = ltc_seq.size() -1;
4225 ARDOUR::frameoffset_t video_start_offset =
4226 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4227 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4228 video_timeline->set_offset(video_start_offset);
4232 _session->maybe_update_session_range(
4233 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4234 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4237 if (add_video_dialog->launch_xjadeo() && local_file) {
4238 editor->set_xjadeo_sensitive(true);
4239 editor->toggle_xjadeo_proc(1);
4241 editor->toggle_xjadeo_proc(0);
4243 editor->toggle_ruler_video(true);
4248 ARDOUR_UI::remove_video ()
4250 video_timeline->close_session();
4251 editor->toggle_ruler_video(false);
4254 video_timeline->set_offset_locked(false);
4255 video_timeline->set_offset(0);
4257 /* delete session state */
4258 XMLNode* node = new XMLNode(X_("Videotimeline"));
4259 _session->add_extra_xml(*node);
4260 node = new XMLNode(X_("Videomonitor"));
4261 _session->add_extra_xml(*node);
4262 node = new XMLNode(X_("Videoexport"));
4263 _session->add_extra_xml(*node);
4264 stop_video_server();
4268 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4270 if (localcacheonly) {
4271 video_timeline->vmon_update();
4273 video_timeline->flush_cache();
4275 editor->queue_visual_videotimeline_update();
4279 ARDOUR_UI::export_video (bool range)
4281 if (ARDOUR::Config->get_show_video_export_info()) {
4282 ExportVideoInfobox infobox (_session);
4283 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4284 if (infobox.show_again()) {
4285 ARDOUR::Config->set_show_video_export_info(false);
4288 case GTK_RESPONSE_YES:
4289 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4295 export_video_dialog->set_session (_session);
4296 export_video_dialog->apply_state(editor->get_selection().time, range);
4297 export_video_dialog->run ();
4298 export_video_dialog->hide ();
4302 ARDOUR_UI::mixer_settings () const
4307 node = _session->instant_xml(X_("Mixer"));
4309 node = Config->instant_xml(X_("Mixer"));
4313 node = new XMLNode (X_("Mixer"));
4320 ARDOUR_UI::main_window_settings () const
4325 node = _session->instant_xml(X_("Main"));
4327 node = Config->instant_xml(X_("Main"));
4331 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4332 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4337 node = new XMLNode (X_("Main"));
4344 ARDOUR_UI::editor_settings () const
4349 node = _session->instant_xml(X_("Editor"));
4351 node = Config->instant_xml(X_("Editor"));
4355 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4356 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4361 node = new XMLNode (X_("Editor"));
4368 ARDOUR_UI::keyboard_settings () const
4372 node = Config->extra_xml(X_("Keyboard"));
4375 node = new XMLNode (X_("Keyboard"));
4382 ARDOUR_UI::create_xrun_marker (framepos_t where)
4385 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4386 _session->locations()->add (location);
4391 ARDOUR_UI::halt_on_xrun_message ()
4393 cerr << "HALT on xrun\n";
4394 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4399 ARDOUR_UI::xrun_handler (framepos_t where)
4405 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4407 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4408 create_xrun_marker(where);
4411 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4412 halt_on_xrun_message ();
4417 ARDOUR_UI::disk_overrun_handler ()
4419 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4421 if (!have_disk_speed_dialog_displayed) {
4422 have_disk_speed_dialog_displayed = true;
4423 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4424 The disk system on your computer\n\
4425 was not able to keep up with %1.\n\
4427 Specifically, it failed to write data to disk\n\
4428 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4429 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4435 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4436 static MessageDialog *scan_dlg = NULL;
4437 static ProgressBar *scan_pbar = NULL;
4438 static HBox *scan_tbox = NULL;
4439 static Gtk::Button *scan_timeout_button;
4442 ARDOUR_UI::cancel_plugin_scan ()
4444 PluginManager::instance().cancel_plugin_scan();
4448 ARDOUR_UI::cancel_plugin_timeout ()
4450 PluginManager::instance().cancel_plugin_timeout();
4451 scan_timeout_button->set_sensitive (false);
4455 ARDOUR_UI::plugin_scan_timeout (int timeout)
4457 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4461 scan_pbar->set_sensitive (false);
4462 scan_timeout_button->set_sensitive (true);
4463 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4466 scan_pbar->set_sensitive (false);
4467 scan_timeout_button->set_sensitive (false);
4473 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4475 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4479 const bool cancelled = PluginManager::instance().cancelled();
4480 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4481 if (cancelled && scan_dlg->is_mapped()) {
4486 if (cancelled || !can_cancel) {
4491 static Gtk::Button *cancel_button;
4493 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4494 VBox* vbox = scan_dlg->get_vbox();
4495 vbox->set_size_request(400,-1);
4496 scan_dlg->set_title (_("Scanning for plugins"));
4498 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4499 cancel_button->set_name ("EditorGTKButton");
4500 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4501 cancel_button->show();
4503 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4505 scan_tbox = manage( new HBox() );
4507 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4508 scan_timeout_button->set_name ("EditorGTKButton");
4509 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4510 scan_timeout_button->show();
4512 scan_pbar = manage(new ProgressBar());
4513 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4514 scan_pbar->set_text(_("Scan Timeout"));
4517 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4518 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4520 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4523 assert(scan_dlg && scan_tbox && cancel_button);
4525 if (type == X_("closeme")) {
4529 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4532 if (!can_cancel || !cancelled) {
4533 scan_timeout_button->set_sensitive(false);
4535 cancel_button->set_sensitive(can_cancel && !cancelled);
4541 ARDOUR_UI::gui_idle_handler ()
4544 /* due to idle calls, gtk_events_pending() may always return true */
4545 while (gtk_events_pending() && --timeout) {
4546 gtk_main_iteration ();
4551 ARDOUR_UI::disk_underrun_handler ()
4553 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4555 if (!have_disk_speed_dialog_displayed) {
4556 have_disk_speed_dialog_displayed = true;
4557 MessageDialog* msg = new MessageDialog (
4558 _main_window, string_compose (_("The disk system on your computer\n\
4559 was not able to keep up with %1.\n\
4561 Specifically, it failed to read data from disk\n\
4562 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4563 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4569 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4571 have_disk_speed_dialog_displayed = false;
4576 ARDOUR_UI::session_dialog (std::string msg)
4578 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4582 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4589 ARDOUR_UI::pending_state_dialog ()
4591 HBox* hbox = manage (new HBox());
4592 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4593 ArdourDialog dialog (_("Crash Recovery"), true);
4594 Label message (string_compose (_("\
4595 This session appears to have been in the\n\
4596 middle of recording when %1 or\n\
4597 the computer was shutdown.\n\
4599 %1 can recover any captured audio for\n\
4600 you, or it can ignore it. Please decide\n\
4601 what you would like to do.\n"), PROGRAM_NAME));
4602 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4603 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4604 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4605 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4606 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4607 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4608 dialog.set_default_response (RESPONSE_ACCEPT);
4609 dialog.set_position (WIN_POS_CENTER);
4614 switch (dialog.run ()) {
4615 case RESPONSE_ACCEPT:
4623 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4625 HBox* hbox = new HBox();
4626 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4627 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4628 Label message (string_compose (_("\
4629 This session was created with a sample rate of %1 Hz, but\n\
4630 %2 is currently running at %3 Hz. If you load this session,\n\
4631 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4633 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4634 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4635 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4636 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4637 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4638 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4639 dialog.set_default_response (RESPONSE_ACCEPT);
4640 dialog.set_position (WIN_POS_CENTER);
4645 switch (dialog.run()) {
4646 case RESPONSE_ACCEPT:
4656 ARDOUR_UI::use_config ()
4658 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4660 set_transport_controllable_state (*node);
4665 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4667 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4668 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4670 primary_clock->set (pos);
4673 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4674 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4676 secondary_clock->set (pos);
4679 if (big_clock_window) {
4680 big_clock->set (pos);
4682 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4686 ARDOUR_UI::step_edit_status_change (bool yn)
4688 // XXX should really store pre-step edit status of things
4689 // we make insensitive
4692 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4693 rec_button.set_sensitive (false);
4695 rec_button.unset_active_state ();;
4696 rec_button.set_sensitive (true);
4701 ARDOUR_UI::record_state_changed ()
4703 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4705 if (!_session || !big_clock_window) {
4706 /* why bother - the clock isn't visible */
4710 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4711 big_clock->set_active (true);
4713 big_clock->set_active (false);
4718 ARDOUR_UI::first_idle ()
4721 _session->allow_auto_play (true);
4725 editor->first_idle();
4728 Keyboard::set_can_save_keybindings (true);
4733 ARDOUR_UI::store_clock_modes ()
4735 XMLNode* node = new XMLNode(X_("ClockModes"));
4737 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4738 XMLNode* child = new XMLNode (X_("Clock"));
4740 child->add_property (X_("name"), (*x)->name());
4741 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4742 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4744 node->add_child_nocopy (*child);
4747 _session->add_extra_xml (*node);
4748 _session->set_dirty ();
4751 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4752 : Controllable (name), ui (u), type(tp)
4758 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4761 /* do nothing: these are radio-style actions */
4765 const char *action = 0;
4769 action = X_("Roll");
4772 action = X_("Stop");
4775 action = X_("GotoStart");
4778 action = X_("GotoEnd");
4781 action = X_("Loop");
4784 action = X_("PlaySelection");
4787 action = X_("Record");
4797 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4805 ARDOUR_UI::TransportControllable::get_value (void) const
4832 ARDOUR_UI::setup_profile ()
4834 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4835 Profile->set_small_screen ();
4838 if (g_getenv ("ARDOUR_SAE")) {
4839 Profile->set_sae ();
4840 Profile->set_single_package ();
4843 if (g_getenv ("TRX")) {
4844 Profile->set_trx ();
4847 if (g_getenv ("MIXBUS")) {
4848 Profile->set_mixbus ();
4853 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4855 MissingFileDialog dialog (s, str, type);
4860 int result = dialog.run ();
4867 return 1; // quit entire session load
4870 result = dialog.get_action ();
4876 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4878 AmbiguousFileDialog dialog (file, hits);
4885 return dialog.get_which ();
4888 /** Allocate our thread-local buffers */
4890 ARDOUR_UI::get_process_buffers ()
4892 _process_thread->get_buffers ();
4895 /** Drop our thread-local buffers */
4897 ARDOUR_UI::drop_process_buffers ()
4899 _process_thread->drop_buffers ();
4903 ARDOUR_UI::feedback_detected ()
4905 _feedback_exists = true;
4909 ARDOUR_UI::successful_graph_sort ()
4911 _feedback_exists = false;
4915 ARDOUR_UI::midi_panic ()
4918 _session->midi_panic();
4923 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4925 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4926 const char* end_big = "</span>";
4927 const char* start_mono = "<tt>";
4928 const char* end_mono = "</tt>";
4930 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4931 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4932 "From now on, use the -2000 version with older versions of %3"),
4933 xml_path, backup_path, PROGRAM_NAME,
4935 start_mono, end_mono), true);
4942 ARDOUR_UI::reset_peak_display ()
4944 if (!_session || !_session->master_out() || !editor_meter) return;
4945 editor_meter->clear_meters();
4946 editor_meter_max_peak = -INFINITY;
4947 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4951 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4953 if (!_session || !_session->master_out()) return;
4954 if (group == _session->master_out()->route_group()) {
4955 reset_peak_display ();
4960 ARDOUR_UI::reset_route_peak_display (Route* route)
4962 if (!_session || !_session->master_out()) return;
4963 if (_session->master_out().get() == route) {
4964 reset_peak_display ();
4969 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4971 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4972 audio_midi_setup->set_position (WIN_POS_CENTER);
4977 response = audio_midi_setup->run();
4979 case Gtk::RESPONSE_OK:
4980 if (!AudioEngine::instance()->running()) {
4994 ARDOUR_UI::transport_numpad_timeout ()
4996 _numpad_locate_happening = false;
4997 if (_numpad_timeout_connection.connected() )
4998 _numpad_timeout_connection.disconnect();
5003 ARDOUR_UI::transport_numpad_decimal ()
5005 _numpad_timeout_connection.disconnect();
5007 if (_numpad_locate_happening) {
5008 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
5009 _numpad_locate_happening = false;
5011 _pending_locate_num = 0;
5012 _numpad_locate_happening = true;
5013 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
5018 ARDOUR_UI::transport_numpad_event (int num)
5020 if ( _numpad_locate_happening ) {
5021 _pending_locate_num = _pending_locate_num*10 + num;
5024 case 0: toggle_roll(false, false); break;
5025 case 1: transport_rewind(1); break;
5026 case 2: transport_forward(1); break;
5027 case 3: transport_record(true); break;
5028 case 4: toggle_session_auto_loop(); break;
5029 case 5: transport_record(false); toggle_session_auto_loop(); break;
5030 case 6: toggle_punch(); break;
5031 case 7: toggle_click(); break;
5032 case 8: toggle_auto_return(); break;
5033 case 9: toggle_follow_edits(); break;
5039 ARDOUR_UI::set_flat_buttons ()
5041 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5045 ARDOUR_UI::audioengine_became_silent ()
5047 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5049 Gtk::MESSAGE_WARNING,
5053 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5055 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5056 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5057 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5058 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5059 Gtk::HBox pay_button_box;
5060 Gtk::HBox subscribe_button_box;
5062 pay_button_box.pack_start (pay_button, true, false);
5063 subscribe_button_box.pack_start (subscribe_button, true, false);
5065 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 */
5067 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5068 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5070 msg.get_vbox()->pack_start (pay_label);
5071 msg.get_vbox()->pack_start (pay_button_box);
5072 msg.get_vbox()->pack_start (subscribe_label);
5073 msg.get_vbox()->pack_start (subscribe_button_box);
5075 msg.get_vbox()->show_all ();
5077 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5078 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5079 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5084 case Gtk::RESPONSE_YES:
5085 AudioEngine::instance()->reset_silence_countdown ();
5088 case Gtk::RESPONSE_NO:
5090 save_state_canfail ("");
5094 case Gtk::RESPONSE_CANCEL:
5096 /* don't reset, save session and exit */
5102 ARDOUR_UI::hide_application ()
5104 Application::instance ()-> hide ();
5108 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5110 /* icons, titles, WM stuff */
5112 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5114 if (window_icons.empty()) {
5115 Glib::RefPtr<Gdk::Pixbuf> icon;
5116 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5117 window_icons.push_back (icon);
5119 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5120 window_icons.push_back (icon);
5122 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5123 window_icons.push_back (icon);
5125 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5126 window_icons.push_back (icon);
5130 if (!window_icons.empty()) {
5131 window.set_default_icon_list (window_icons);
5134 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5136 if (!name.empty()) {
5140 window.set_title (title.get_string());
5141 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5143 window.set_flags (CAN_FOCUS);
5144 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5146 /* This is a hack to ensure that GTK-accelerators continue to
5147 * work. Once we switch over to entirely native bindings, this will be
5148 * unnecessary and should be removed
5150 window.add_accel_group (ActionManager::ui_manager->get_accel_group());
5152 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5153 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5154 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5155 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5159 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
5161 Gtkmm2ext::Bindings* bindings = 0;
5162 Gtk::Window* window = 0;
5164 /* until we get ardour bindings working, we are not handling key
5168 if (ev->type != GDK_KEY_PRESS) {
5172 if (event_window == &_main_window) {
5174 window = event_window;
5176 /* find current tab contents */
5178 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5180 /* see if it uses the ardour binding system */
5183 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
5186 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
5188 } else if (event_window != 0) {
5190 window = event_window;
5192 /* see if window uses ardour binding system */
5194 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
5197 /* An empty binding set is treated as if it doesn't exist */
5199 if (bindings && bindings->empty()) {
5203 return key_press_focus_accelerator_handler (*window, ev, bindings);
5207 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* bindings)
5209 GtkWindow* win = window.gobj();
5210 GtkWidget* focus = gtk_window_get_focus (win);
5211 bool special_handling_of_unmodified_accelerators = false;
5212 /* consider all relevant modifiers but not LOCK or SHIFT */
5213 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
5215 GdkModifierType modifier = GdkModifierType (ev->state);
5216 modifier = GdkModifierType (modifier & gtk_accelerator_get_default_mod_mask());
5217 Gtkmm2ext::possibly_translate_mod_to_make_legal_accelerator(modifier);
5221 /* some widget has keyboard focus */
5223 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
5225 /* A particular kind of focusable widget currently has keyboard
5226 * focus. All unmodified key events should go to that widget
5227 * first and not be used as an accelerator by default
5230 special_handling_of_unmodified_accelerators = true;
5234 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 focus = %7 (%8) Key event: code = %2 state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7\n",
5237 show_gdk_event_state (ev->state),
5238 special_handling_of_unmodified_accelerators,
5239 Keyboard::some_magic_widget_has_focus(),
5241 (focus ? gtk_widget_get_name (focus) : "no focus widget")));
5243 /* This exists to allow us to override the way GTK handles
5244 key events. The normal sequence is:
5246 a) event is delivered to a GtkWindow
5247 b) accelerators/mnemonics are activated
5248 c) if (b) didn't handle the event, propagate to
5249 the focus widget and/or focus chain
5251 The problem with this is that if the accelerators include
5252 keys without modifiers, such as the space bar or the
5253 letter "e", then pressing the key while typing into
5254 a text entry widget results in the accelerator being
5255 activated, instead of the desired letter appearing
5258 There is no good way of fixing this, but this
5259 represents a compromise. The idea is that
5260 key events involving modifiers (not Shift)
5261 get routed into the activation pathway first, then
5262 get propagated to the focus widget if necessary.
5264 If the key event doesn't involve modifiers,
5265 we deliver to the focus widget first, thus allowing
5266 it to get "normal text" without interference
5269 Of course, this can also be problematic: if there
5270 is a widget with focus, then it will swallow
5271 all "normal text" accelerators.
5275 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
5277 /* no special handling or there are modifiers in effect: accelerate first */
5279 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
5280 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tevent send-event:%1 time:%2 length:%3 name %7 string:%4 hardware_keycode:%5 group:%6\n",
5281 ev->send_event, ev->time, ev->length, ev->string, ev->hardware_keycode, ev->group, gdk_keyval_name (ev->keyval)));
5283 DEBUG_TRACE (DEBUG::Accelerators, "\tsending to window\n");
5284 KeyboardKey k (ev->state, ev->keyval);
5288 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing Ardour bindings %1 for this event\n", bindings));
5290 if (bindings->activate (k, Bindings::Press)) {
5291 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5296 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5298 if (global_bindings->activate (k, Bindings::Press)) {
5299 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5303 DEBUG_TRACE (DEBUG::Accelerators, "\tnot accelerated, now propagate\n");
5305 if (gtk_window_propagate_key_event (win, ev)) {
5306 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
5312 /* no modifiers, propagate first */
5314 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
5316 if (gtk_window_propagate_key_event (win, ev)) {
5317 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
5321 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
5322 KeyboardKey k (ev->state, ev->keyval);
5326 DEBUG_TRACE (DEBUG::Accelerators, "\tusing Ardour bindings for this window\n");
5329 if (bindings->activate (k, Bindings::Press)) {
5330 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5336 DEBUG_TRACE (DEBUG::Accelerators, "\tnot yet handled, try global bindings\n");
5338 if (global_bindings->activate (k, Bindings::Press)) {
5339 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
5344 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
5349 ARDOUR_UI::load_bindings ()
5351 if ((global_bindings = Bindings::get_bindings ("global", global_actions)) == 0) {
5352 error << _("Global keybindings are missing") << endmsg;