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 "binding_owners.h"
115 #include "bundle_manager.h"
116 #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 , ignore_dual_punch (false)
246 , _mixer_on_top (false)
247 , _initial_verbose_plugin_scan (false)
248 , first_time_engine_run (true)
249 , roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
250 , stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
251 , goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
252 , goto_end_controllable (new TransportControllable ("transport goto end", *this, TransportControllable::GotoEnd))
253 , auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
254 , play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
255 , rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
256 , auto_return_button (ArdourButton::led_default_elements)
257 , follow_edits_button (ArdourButton::led_default_elements)
258 , auto_input_button (ArdourButton::led_default_elements)
259 , auditioning_alert_button (_("Audition"))
260 , solo_alert_button (_("Solo"))
261 , feedback_alert_button (_("Feedback"))
262 , error_alert_button ( ArdourButton::just_led_default_elements )
264 , editor_meter_peak_display()
265 , _numpad_locate_happening (false)
266 , _session_is_new (false)
267 , last_key_press_time (0)
270 , rc_option_editor (0)
271 , speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
272 , key_editor (X_("key-editor"), _("Key Bindings"))
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 Tracks/Busses"), 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 , video_server_process (0)
287 , have_configure_timeout (false)
288 , last_configure_time (0)
290 , have_disk_speed_dialog_displayed (false)
291 , _status_bar_visibility (X_("status-bar"))
292 , _feedback_exists (false)
293 , _log_not_acknowledged (LogLevelNone)
294 , duplicate_routes_dialog (0)
296 Gtkmm2ext::init (localedir);
298 UIConfiguration::instance().post_gui_init ();
300 if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
301 MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
303 /* configuration was modified, exit immediately */
307 if (theArdourUI == 0) {
311 /* stop libxml from spewing to stdout/stderr */
313 xmlSetGenericErrorFunc (this, libxml_generic_error_func);
314 xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
316 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
317 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
318 UIConfiguration::instance().map_parameters (pc);
320 roll_button.set_controllable (roll_controllable);
321 stop_button.set_controllable (stop_controllable);
322 goto_start_button.set_controllable (goto_start_controllable);
323 goto_end_button.set_controllable (goto_end_controllable);
324 auto_loop_button.set_controllable (auto_loop_controllable);
325 play_selection_button.set_controllable (play_selection_controllable);
326 rec_button.set_controllable (rec_controllable);
328 roll_button.set_name ("transport button");
329 stop_button.set_name ("transport button");
330 goto_start_button.set_name ("transport button");
331 goto_end_button.set_name ("transport button");
332 auto_loop_button.set_name ("transport button");
333 play_selection_button.set_name ("transport button");
334 rec_button.set_name ("transport recenable button");
335 midi_panic_button.set_name ("transport button");
337 ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
338 ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
340 ARDOUR::Session::VersionMismatch.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_format_mismatch, this, _1, _2), gui_context());
342 /* handle dialog requests */
344 ARDOUR::Session::Dialog.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::session_dialog, this, _1), gui_context());
346 /* handle pending state with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
348 ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this));
350 /* handle Audio/MIDI setup when session requires it */
352 ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1));
354 /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */
356 ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2));
358 /* handle requests to quit (coming from JACK session) */
360 ARDOUR::Session::Quit.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::finish, this), gui_context ());
362 /* tell the user about feedback */
364 ARDOUR::Session::FeedbackDetected.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::feedback_detected, this), gui_context ());
365 ARDOUR::Session::SuccessfulGraphSort.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::successful_graph_sort, this), gui_context ());
367 /* handle requests to deal with missing files */
369 ARDOUR::Session::MissingFile.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::missing_file, this, _1, _2, _3));
371 /* and ambiguous files */
373 ARDOUR::FileSource::AmbiguousFileName.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::ambiguous_file, this, _1, _2));
375 /* also plugin scan messages */
376 ARDOUR::PluginScanMessage.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_dialog, this, _1, _2, _3), gui_context());
377 ARDOUR::PluginScanTimeout.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::plugin_scan_timeout, this, _1), gui_context());
379 ARDOUR::GUIIdle.connect (forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::gui_idle_handler, this), gui_context());
381 Config->ParameterChanged.connect ( forever_connections, MISSING_INVALIDATOR, boost::bind(&ARDOUR_UI::set_flat_buttons, this), gui_context() );
384 /* lets get this party started */
386 setup_gtk_ardour_enums ();
389 SessionEvent::create_per_thread_pool ("GUI", 4096);
391 /* we like keyboards */
393 keyboard = new ArdourKeyboard(*this);
395 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
397 keyboard->set_state (*node, Stateful::loading_state_version);
400 /* we don't like certain modifiers */
401 Bindings::set_ignored_state (GDK_LOCK_MASK|GDK_MOD2_MASK|GDK_MOD3_MASK);
403 UIConfiguration::instance().reset_dpi ();
405 TimeAxisViewItem::set_constant_heights ();
407 /* Set this up so that our window proxies can register actions */
409 ActionManager::init ();
411 /* The following must happen after ARDOUR::init() so that Config is set up */
413 const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
416 key_editor.set_state (*ui_xml, 0);
417 session_option_editor.set_state (*ui_xml, 0);
418 speaker_config_window.set_state (*ui_xml, 0);
419 about.set_state (*ui_xml, 0);
420 add_route_dialog.set_state (*ui_xml, 0);
421 add_video_dialog.set_state (*ui_xml, 0);
422 route_params.set_state (*ui_xml, 0);
423 bundle_manager.set_state (*ui_xml, 0);
424 location_ui.set_state (*ui_xml, 0);
425 big_clock_window.set_state (*ui_xml, 0);
426 audio_port_matrix.set_state (*ui_xml, 0);
427 midi_port_matrix.set_state (*ui_xml, 0);
428 export_video_dialog.set_state (*ui_xml, 0);
431 // rc_option_editor->set_state (*ui_xml, 0);
432 // editor->set_state (*ui_xml, 0);
433 // mixer->set_state (*ui_xml, 0);
436 WM::Manager::instance().register_window (&key_editor);
437 // WM::Manager::instance().register_window (&rc_option_editor);
438 WM::Manager::instance().register_window (&session_option_editor);
439 WM::Manager::instance().register_window (&speaker_config_window);
440 WM::Manager::instance().register_window (&about);
441 WM::Manager::instance().register_window (&add_route_dialog);
442 WM::Manager::instance().register_window (&add_video_dialog);
443 WM::Manager::instance().register_window (&route_params);
444 WM::Manager::instance().register_window (&audio_midi_setup);
445 WM::Manager::instance().register_window (&export_video_dialog);
446 WM::Manager::instance().register_window (&bundle_manager);
447 WM::Manager::instance().register_window (&location_ui);
448 WM::Manager::instance().register_window (&big_clock_window);
449 WM::Manager::instance().register_window (&audio_port_matrix);
450 WM::Manager::instance().register_window (&midi_port_matrix);
452 /* Trigger setting up the color scheme and loading the GTK RC file */
454 UIConfiguration::instance().load_rc_file (false);
456 _process_thread = new ProcessThread ();
457 _process_thread->init ();
459 UIConfiguration::instance().DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
464 GlobalPortMatrixWindow*
465 ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type)
470 return new GlobalPortMatrixWindow (_session, type);
474 ARDOUR_UI::attach_to_engine ()
476 AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context());
477 ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports);
481 ARDOUR_UI::engine_stopped ()
483 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
484 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
485 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
486 update_sample_rate (0);
491 ARDOUR_UI::engine_running ()
493 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running)
494 if (first_time_engine_run) {
496 first_time_engine_run = false;
500 _session->reset_xrun_count ();
502 update_disk_space ();
504 update_xrun_count ();
505 update_sample_rate (AudioEngine::instance()->sample_rate());
506 update_timecode_format ();
507 update_peak_thread_work ();
508 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, true);
509 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, false);
513 ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
515 if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
516 /* we can't rely on the original string continuing to exist when we are called
517 again in the GUI thread, so make a copy and note that we need to
520 char *copy = strdup (reason);
521 Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
525 ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false);
526 ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true);
528 update_sample_rate (0);
532 /* if the reason is a non-empty string, it means that the backend was shutdown
533 rather than just Ardour.
536 if (strlen (reason)) {
537 msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason);
539 msgstr = string_compose (_("\
540 The audio backend has either been shutdown or it\n\
541 disconnected %1 because %1\n\
542 was not fast enough. Try to restart\n\
543 the audio backend and save the session."), PROGRAM_NAME);
546 MessageDialog msg (_main_window, msgstr);
547 pop_back_splash (msg);
551 free (const_cast<char*> (reason));
556 ARDOUR_UI::post_engine ()
558 /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
560 #ifdef AUDIOUNIT_SUPPORT
562 if (AUPluginInfo::au_get_crashlog(au_msg)) {
563 popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
564 error << _("Audio Unit Plugin Scan Failed:") << endmsg;
565 info << au_msg << endmsg;
569 ARDOUR::init_post_engine ();
571 /* connect to important signals */
573 AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context());
574 AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
575 AudioEngine::instance()->BufferSizeChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context());
576 AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false));
577 AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
579 if (setup_windows ()) {
580 throw failed_constructor ();
583 /* Do this after setup_windows (), as that's when the _status_bar_visibility is created */
584 XMLNode* n = Config->extra_xml (X_("UI"));
586 _status_bar_visibility.set_state (*n);
589 check_memory_locking();
591 /* this is the first point at which all the keybindings are available */
593 if (ARDOUR_COMMAND_LINE::show_key_actions) {
594 vector<string> names;
595 vector<string> paths;
596 vector<string> tooltips;
598 vector<AccelKey> bindings;
600 ActionManager::get_all_actions (names, paths, tooltips, keys, bindings);
602 vector<string>::iterator n;
603 vector<string>::iterator k;
604 vector<string>::iterator p;
605 for (n = names.begin(), k = keys.begin(), p = paths.begin(); n != names.end(); ++n, ++k, ++p) {
606 cout << "Action: '" << (*n) << "' bound to '" << (*k) << "' Path: '" << (*p) << "'" << endl;
609 halt_connection.disconnect ();
610 AudioEngine::instance()->stop ();
614 /* this being a GUI and all, we want peakfiles */
616 AudioFileSource::set_build_peakfiles (true);
617 AudioFileSource::set_build_missing_peakfiles (true);
619 /* set default clock modes */
621 if (Profile->get_sae()) {
622 primary_clock->set_mode (AudioClock::BBT);
623 secondary_clock->set_mode (AudioClock::MinSec);
625 primary_clock->set_mode (AudioClock::Timecode);
626 secondary_clock->set_mode (AudioClock::BBT);
629 /* start the time-of-day-clock */
632 /* OS X provides a nearly-always visible wallclock, so don't be stupid */
633 update_wall_clock ();
634 Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
639 Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
640 boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
641 Config->map_parameters (pc);
643 UIConfiguration::instance().map_parameters (pc);
647 ARDOUR_UI::~ARDOUR_UI ()
649 UIConfiguration::instance().save_state();
653 if (getenv ("ARDOUR_RUNNING_UNDER_VALGRIND")) {
654 // don't bother at 'real' exit. the OS cleans up for us.
656 delete primary_clock;
657 delete secondary_clock;
658 delete _process_thread;
663 delete gui_object_state;
664 FastMeter::flush_pattern_cache ();
665 PixFader::flush_pattern_cache ();
669 /* Small trick to flush main-thread event pool.
670 * Other thread-pools are destroyed at pthread_exit(),
671 * but tmain thread termination is too late to trigger Pool::~Pool()
673 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.
674 delete ev->event_pool();
679 ARDOUR_UI::pop_back_splash (Gtk::Window& win)
681 if (Splash::instance()) {
682 Splash::instance()->pop_back_for (win);
687 ARDOUR_UI::configure_timeout ()
689 if (last_configure_time == 0) {
690 /* no configure events yet */
694 /* force a gap of 0.5 seconds since the last configure event
697 if (get_microseconds() - last_configure_time < 500000) {
700 have_configure_timeout = false;
701 save_ardour_state ();
707 ARDOUR_UI::configure_handler (GdkEventConfigure* /*conf*/)
709 if (have_configure_timeout) {
710 last_configure_time = get_microseconds();
712 Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
713 have_configure_timeout = true;
720 ARDOUR_UI::set_transport_controllable_state (const XMLNode& node)
722 const XMLProperty* prop;
724 if ((prop = node.property ("roll")) != 0) {
725 roll_controllable->set_id (prop->value());
727 if ((prop = node.property ("stop")) != 0) {
728 stop_controllable->set_id (prop->value());
730 if ((prop = node.property ("goto-start")) != 0) {
731 goto_start_controllable->set_id (prop->value());
733 if ((prop = node.property ("goto-end")) != 0) {
734 goto_end_controllable->set_id (prop->value());
736 if ((prop = node.property ("auto-loop")) != 0) {
737 auto_loop_controllable->set_id (prop->value());
739 if ((prop = node.property ("play-selection")) != 0) {
740 play_selection_controllable->set_id (prop->value());
742 if ((prop = node.property ("rec")) != 0) {
743 rec_controllable->set_id (prop->value());
745 if ((prop = node.property ("shuttle")) != 0) {
746 shuttle_box->controllable()->set_id (prop->value());
751 ARDOUR_UI::get_transport_controllable_state ()
753 XMLNode* node = new XMLNode(X_("TransportControllables"));
756 roll_controllable->id().print (buf, sizeof (buf));
757 node->add_property (X_("roll"), buf);
758 stop_controllable->id().print (buf, sizeof (buf));
759 node->add_property (X_("stop"), buf);
760 goto_start_controllable->id().print (buf, sizeof (buf));
761 node->add_property (X_("goto_start"), buf);
762 goto_end_controllable->id().print (buf, sizeof (buf));
763 node->add_property (X_("goto_end"), buf);
764 auto_loop_controllable->id().print (buf, sizeof (buf));
765 node->add_property (X_("auto_loop"), buf);
766 play_selection_controllable->id().print (buf, sizeof (buf));
767 node->add_property (X_("play_selection"), buf);
768 rec_controllable->id().print (buf, sizeof (buf));
769 node->add_property (X_("rec"), buf);
770 shuttle_box->controllable()->id().print (buf, sizeof (buf));
771 node->add_property (X_("shuttle"), buf);
777 ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
780 _session->save_state (snapshot_name);
785 ARDOUR_UI::autosave_session ()
787 if (g_main_depth() > 1) {
788 /* inside a recursive main loop,
789 give up because we may not be able to
795 if (!Config->get_periodic_safety_backups()) {
800 _session->maybe_write_autosave();
807 ARDOUR_UI::update_autosave ()
809 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_autosave)
811 if (_session && _session->dirty()) {
812 if (_autosave_connection.connected()) {
813 _autosave_connection.disconnect();
816 _autosave_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &ARDOUR_UI::autosave_session),
817 Config->get_periodic_safety_backup_interval() * 1000);
820 if (_autosave_connection.connected()) {
821 _autosave_connection.disconnect();
827 ARDOUR_UI::check_announcements ()
830 string _annc_filename;
833 _annc_filename = PROGRAM_NAME "_announcements_osx_";
834 #elif defined PLATFORM_WINDOWS
835 _annc_filename = PROGRAM_NAME "_announcements_windows_";
837 _annc_filename = PROGRAM_NAME "_announcements_linux_";
839 _annc_filename.append (VERSIONSTRING);
841 _announce_string = "";
843 std::string path = Glib::build_filename (user_config_directory(), _annc_filename);
844 FILE* fin = g_fopen (path.c_str(), "rb");
846 while (!feof (fin)) {
849 if ((len = fread (tmp, sizeof(char), 1024, fin)) == 0 || ferror (fin)) {
852 _announce_string.append (tmp, len);
857 pingback (VERSIONSTRING, path);
862 ARDOUR_UI::starting ()
864 Application* app = Application::instance ();
866 bool brand_new_user = ArdourStartup::required ();
868 app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish));
869 app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
871 if (ARDOUR_COMMAND_LINE::check_announcements) {
872 check_announcements ();
877 /* we need to create this early because it may need to set the
878 * audio backend end up.
882 audio_midi_setup.get (true);
884 std::cerr << "audio-midi engine setup failed."<< std::endl;
888 if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
889 nsm = new NSM_Client;
890 if (!nsm->init (nsm_url)) {
891 /* the ardour executable may have different names:
893 * waf's obj.target for distro versions: eg ardour4, ardourvst4
894 * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
895 * argv[0] does not apply since we need the wrapper-script (not the binary itself)
897 * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
899 const char *process_name = g_getenv ("ARDOUR_SELF");
900 nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
903 // wait for announce reply from nsm server
904 for ( i = 0; i < 5000; ++i) {
908 if (nsm->is_active()) {
913 error << _("NSM server did not announce itself") << endmsg;
916 // wait for open command from nsm server
917 for ( i = 0; i < 5000; ++i) {
920 if (nsm->client_id ()) {
926 error << _("NSM: no client ID provided") << endmsg;
930 if (_session && nsm) {
931 _session->set_nsm_state( nsm->is_active() );
933 error << _("NSM: no session created") << endmsg;
937 // nsm requires these actions disabled
938 vector<string> action_names;
939 action_names.push_back("SaveAs");
940 action_names.push_back("Rename");
941 action_names.push_back("New");
942 action_names.push_back("Open");
943 action_names.push_back("Recent");
944 action_names.push_back("Close");
946 for (vector<string>::const_iterator n = action_names.begin(); n != action_names.end(); ++n) {
947 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), (*n).c_str());
949 act->set_sensitive (false);
956 error << _("NSM: initialization failed") << endmsg;
962 if (brand_new_user) {
963 _initial_verbose_plugin_scan = true;
968 _initial_verbose_plugin_scan = false;
969 switch (s.response ()) {
970 case Gtk::RESPONSE_OK:
977 #ifdef NO_PLUGIN_STATE
979 ARDOUR::RecentSessions rs;
980 ARDOUR::read_recent_sessions (rs);
982 string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
984 if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
986 /* already used Ardour, have sessions ... warn about plugin state */
988 ArdourDialog d (_("Free/Demo Version Warning"), true);
990 Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
991 CheckButton c (_("Don't warn me about this again"));
993 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"),
994 string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
995 _("It will not restore OR save any plugin settings"),
996 _("If you load an existing session with plugin settings\n"
997 "they will not be used and will be lost."),
998 _("To get full access to updates without this limitation\n"
999 "consider becoming a subscriber for a low cost every month.")));
1000 l.set_justify (JUSTIFY_CENTER);
1002 b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
1004 d.get_vbox()->pack_start (l, true, true);
1005 d.get_vbox()->pack_start (b, false, false, 12);
1006 d.get_vbox()->pack_start (c, false, false, 12);
1008 d.add_button (_("Quit now"), RESPONSE_CANCEL);
1009 d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
1013 c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
1015 if (d.run () != RESPONSE_OK) {
1021 /* go get a session */
1023 const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
1025 if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) {
1026 std::cerr << "Cannot get session parameters."<< std::endl;
1033 goto_editor_window ();
1035 WM::Manager::instance().show_visible ();
1037 /* We have to do this here since goto_editor_window() ends up calling show_all() on the
1038 * editor window, and we may want stuff to be hidden.
1040 _status_bar_visibility.update ();
1042 BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
1047 ARDOUR_UI::check_memory_locking ()
1049 #if defined(__APPLE__) || defined(PLATFORM_WINDOWS)
1050 /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */
1054 XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"));
1056 if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) {
1058 struct rlimit limits;
1060 long pages, page_size;
1062 size_t pages_len=sizeof(pages);
1063 if ((page_size = getpagesize()) < 0 ||
1064 sysctlbyname("hw.availpages", &pages, &pages_len, NULL, 0))
1066 if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0)
1071 ram = (int64_t) pages * (int64_t) page_size;
1074 if (getrlimit (RLIMIT_MEMLOCK, &limits)) {
1078 if (limits.rlim_cur != RLIM_INFINITY) {
1080 if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) {
1084 _("WARNING: Your system has a limit for maximum amount of locked memory. "
1085 "This might cause %1 to run out of memory before your system "
1086 "runs out of memory. \n\n"
1087 "You can view the memory limit with 'ulimit -l', "
1088 "and it is normally controlled by %2"),
1091 X_("/etc/login.conf")
1093 X_(" /etc/security/limits.conf")
1097 msg.set_default_response (RESPONSE_OK);
1099 VBox* vbox = msg.get_vbox();
1101 CheckButton cb (_("Do not show this window again"));
1102 hbox.pack_start (cb, true, false);
1103 vbox->pack_start (hbox);
1108 pop_back_splash (msg);
1112 if (cb.get_active()) {
1113 XMLNode node (X_("no-memory-warning"));
1114 Config->add_instant_xml (node);
1119 #endif // !__APPLE__
1124 ARDOUR_UI::queue_finish ()
1126 Glib::signal_idle().connect (mem_fun (*this, &ARDOUR_UI::idle_finish));
1130 ARDOUR_UI::idle_finish ()
1133 return false; /* do not call again */
1140 ARDOUR_UI::instance()->video_timeline->sync_session_state();
1142 if (_session->dirty()) {
1143 vector<string> actions;
1144 actions.push_back (_("Don't quit"));
1145 actions.push_back (_("Just quit"));
1146 actions.push_back (_("Save and quit"));
1147 switch (ask_about_saving_session(actions)) {
1152 /* use the default name */
1153 if (save_state_canfail ("")) {
1154 /* failed - don't quit */
1155 MessageDialog msg (_main_window,
1156 string_compose (_("\
1157 %1 was unable to save your session.\n\n\
1158 If you still wish to quit, please use the\n\n\
1159 \"Just quit\" option."), PROGRAM_NAME));
1160 pop_back_splash(msg);
1170 second_connection.disconnect ();
1171 point_one_second_connection.disconnect ();
1172 point_zero_something_second_connection.disconnect();
1173 fps_connection.disconnect();
1176 delete ARDOUR_UI::instance()->video_timeline;
1177 ARDOUR_UI::instance()->video_timeline = NULL;
1178 stop_video_server();
1180 /* Save state before deleting the session, as that causes some
1181 windows to be destroyed before their visible state can be
1184 save_ardour_state ();
1186 close_all_dialogs ();
1189 _session->set_clean ();
1190 _session->remove_pending_capture_state ();
1195 halt_connection.disconnect ();
1196 AudioEngine::instance()->stop ();
1197 #ifdef WINDOWS_VST_SUPPORT
1198 fst_stop_threading();
1204 ARDOUR_UI::ask_about_saving_session (const vector<string>& actions)
1206 ArdourDialog window (_("Unsaved Session"));
1207 Gtk::HBox dhbox; // the hbox for the image and text
1208 Gtk::Label prompt_label;
1209 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG));
1213 assert (actions.size() >= 3);
1215 window.add_button (actions[0], RESPONSE_REJECT);
1216 window.add_button (actions[1], RESPONSE_APPLY);
1217 window.add_button (actions[2], RESPONSE_ACCEPT);
1219 window.set_default_response (RESPONSE_ACCEPT);
1221 Gtk::Button noquit_button (msg);
1222 noquit_button.set_name ("EditorGTKButton");
1226 if (_session->snap_name() == _session->name()) {
1227 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?"),
1228 _session->snap_name());
1230 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?"),
1231 _session->snap_name());
1234 prompt_label.set_text (prompt);
1235 prompt_label.set_name (X_("PrompterLabel"));
1236 prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP);
1238 dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP);
1239 dhbox.set_homogeneous (false);
1240 dhbox.pack_start (*dimage, false, false, 5);
1241 dhbox.pack_start (prompt_label, true, false, 5);
1242 window.get_vbox()->pack_start (dhbox);
1244 window.set_name (_("Prompter"));
1245 window.set_modal (true);
1246 window.set_resizable (false);
1249 prompt_label.show();
1254 ResponseType r = (ResponseType) window.run();
1259 case RESPONSE_ACCEPT: // save and get out of here
1261 case RESPONSE_APPLY: // get out of here
1272 ARDOUR_UI::every_second ()
1275 update_xrun_count ();
1276 update_buffer_load ();
1277 update_disk_space ();
1278 update_timecode_format ();
1279 update_peak_thread_work ();
1281 if (nsm && nsm->is_active ()) {
1284 if (!_was_dirty && _session->dirty ()) {
1288 else if (_was_dirty && !_session->dirty ()){
1296 ARDOUR_UI::every_point_one_seconds ()
1298 // TODO get rid of this..
1299 // ShuttleControl is updated directly via TransportStateChange signal
1303 ARDOUR_UI::every_point_zero_something_seconds ()
1305 // august 2007: actual update frequency: 25Hz (40ms), not 100Hz
1307 if (editor_meter && UIConfiguration::instance().get_show_editor_meter()) {
1308 float mpeak = editor_meter->update_meters();
1309 if (mpeak > editor_meter_max_peak) {
1310 if (mpeak >= UIConfiguration::instance().get_meter_peak()) {
1311 editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
1318 ARDOUR_UI::set_fps_timeout_connection ()
1320 unsigned int interval = 40;
1321 if (!_session) return;
1322 if (_session->timecode_frames_per_second() != 0) {
1323 /* ideally we'll use a select() to sleep and not accumulate
1324 * idle time to provide a regular periodic signal.
1325 * See linux_vst_gui_support.cc 'elapsed_time_ms'.
1326 * However, that'll require a dedicated thread and cross-thread
1327 * signals to the GUI Thread..
1329 interval = floor(500. /* update twice per FPS, since Glib::signal_timeout is very irregular */
1330 * _session->frame_rate() / _session->nominal_frame_rate()
1331 / _session->timecode_frames_per_second()
1333 #ifdef PLATFORM_WINDOWS
1334 // the smallest windows scheduler time-slice is ~15ms.
1335 // periodic GUI timeouts shorter than that will cause
1336 // WaitForSingleObject to spinlock (100% of one CPU Core)
1337 // and gtk never enters idle mode.
1338 // also changing timeBeginPeriod(1) does not affect that in
1339 // any beneficial way, so we just limit the max rate for now.
1340 interval = std::max(30u, interval); // at most ~33Hz.
1342 interval = std::max(8u, interval); // at most 120Hz.
1345 fps_connection.disconnect();
1346 Timers::set_fps_interval (interval);
1350 ARDOUR_UI::update_sample_rate (framecnt_t)
1354 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored)
1356 if (!AudioEngine::instance()->connected()) {
1358 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1362 framecnt_t rate = AudioEngine::instance()->sample_rate();
1365 /* no sample rate available */
1366 snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
1369 if (fmod (rate, 1000.0) != 0.0) {
1370 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
1371 (float) rate / 1000.0f,
1372 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1374 snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
1376 (AudioEngine::instance()->usecs_per_cycle() / 1000.0f));
1380 sample_rate_label.set_markup (buf);
1384 ARDOUR_UI::update_format ()
1387 format_label.set_text ("");
1392 s << _("File:") << X_(" <span foreground=\"green\">");
1394 switch (_session->config.get_native_file_header_format ()) {
1426 switch (_session->config.get_native_file_data_format ()) {
1440 format_label.set_markup (s.str ());
1444 ARDOUR_UI::update_xrun_count ()
1448 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1449 should also be changed.
1453 const unsigned int x = _session->get_xrun_count ();
1455 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
1457 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
1460 snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
1462 xrun_label.set_markup (buf);
1463 set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
1467 ARDOUR_UI::update_cpu_load ()
1471 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1472 should also be changed.
1475 double const c = AudioEngine::instance()->get_dsp_load ();
1476 snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
1477 cpu_load_label.set_markup (buf);
1481 ARDOUR_UI::update_peak_thread_work ()
1484 const int c = SourceFactory::peak_work_queue_length ();
1486 snprintf (buf, sizeof (buf), _("PkBld: <span foreground=\"%s\">%d</span>"), c >= 2 ? X_("red") : X_("green"), c);
1487 peak_thread_work_label.set_markup (buf);
1489 peak_thread_work_label.set_markup (X_(""));
1494 ARDOUR_UI::update_buffer_load ()
1498 uint32_t const playback = _session ? _session->playback_load () : 100;
1499 uint32_t const capture = _session ? _session->capture_load () : 100;
1501 /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
1502 should also be changed.
1508 _("Buffers: <span foreground=\"green\">p:</span><span foreground=\"%s\">%" PRIu32 "%%</span> "
1509 "<span foreground=\"green\">c:</span><span foreground=\"%s\">%" PRIu32 "%%</span>"),
1510 playback <= 5 ? X_("red") : X_("green"),
1512 capture <= 5 ? X_("red") : X_("green"),
1516 buffer_load_label.set_markup (buf);
1518 buffer_load_label.set_text ("");
1523 ARDOUR_UI::count_recenabled_streams (Route& route)
1525 Track* track = dynamic_cast<Track*>(&route);
1526 if (track && track->record_enabled()) {
1527 rec_enabled_streams += track->n_inputs().n_total();
1532 ARDOUR_UI::update_disk_space()
1534 if (_session == 0) {
1538 boost::optional<framecnt_t> opt_frames = _session->available_capture_duration();
1540 framecnt_t fr = _session->frame_rate();
1543 /* skip update - no SR available */
1548 /* Available space is unknown */
1549 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">Unknown</span>"));
1550 } else if (opt_frames.get_value_or (0) == max_framecnt) {
1551 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
1553 rec_enabled_streams = 0;
1554 _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
1556 framecnt_t frames = opt_frames.get_value_or (0);
1558 if (rec_enabled_streams) {
1559 frames /= rec_enabled_streams;
1566 hrs = frames / (fr * 3600);
1569 snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">>24 hrs</span>"));
1571 frames -= hrs * fr * 3600;
1572 mins = frames / (fr * 60);
1573 frames -= mins * fr * 60;
1576 bool const low = (hrs == 0 && mins <= 30);
1580 _("Disk: <span foreground=\"%s\">%02dh:%02dm:%02ds</span>"),
1581 low ? X_("red") : X_("green"),
1587 disk_space_label.set_markup (buf);
1591 ARDOUR_UI::update_timecode_format ()
1597 TimecodeSlave* tcslave;
1598 SyncSource sync_src = Config->get_sync_source();
1600 if ((sync_src == LTC || sync_src == MTC) && (tcslave = dynamic_cast<TimecodeSlave*>(_session->slave())) != 0) {
1601 matching = (tcslave->apparent_timecode_format() == _session->config.get_timecode_format());
1606 snprintf (buf, sizeof (buf), S_("Timecode|TC: <span foreground=\"%s\">%s</span>"),
1607 matching ? X_("green") : X_("red"),
1608 Timecode::timecode_format_name (_session->config.get_timecode_format()).c_str());
1610 snprintf (buf, sizeof (buf), "TC: n/a");
1613 timecode_format_label.set_markup (buf);
1617 ARDOUR_UI::update_wall_clock ()
1621 static int last_min = -1;
1624 tm_now = localtime (&now);
1625 if (last_min != tm_now->tm_min) {
1627 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1628 wall_clock_label.set_text (buf);
1629 last_min = tm_now->tm_min;
1636 ARDOUR_UI::open_recent_session ()
1638 bool can_return = (_session != 0);
1640 SessionDialog recent_session_dialog;
1644 ResponseType r = (ResponseType) recent_session_dialog.run ();
1647 case RESPONSE_ACCEPT:
1651 recent_session_dialog.hide();
1658 recent_session_dialog.hide();
1662 std::string path = recent_session_dialog.session_folder();
1663 std::string state = recent_session_dialog.session_name (should_be_new);
1665 if (should_be_new == true) {
1669 _session_is_new = false;
1671 if (load_session (path, state) == 0) {
1680 ARDOUR_UI::check_audioengine (Gtk::Window& parent)
1682 if (!AudioEngine::instance()->connected()) {
1683 MessageDialog msg (parent, string_compose (
1684 _("%1 is not connected to any audio backend.\n"
1685 "You cannot open or close sessions in this condition"),
1687 pop_back_splash (msg);
1695 ARDOUR_UI::open_session ()
1697 if (!check_audioengine(*editor)) {
1701 /* ardour sessions are folders */
1702 Gtk::FileChooserDialog open_session_selector(_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
1703 open_session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1704 open_session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
1705 open_session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
1708 string session_parent_dir = Glib::path_get_dirname(_session->path());
1709 open_session_selector.set_current_folder(session_parent_dir);
1711 open_session_selector.set_current_folder(Config->get_default_session_parent_dir());
1714 Gtkmm2ext::add_volume_shortcuts (open_session_selector);
1716 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
1717 string default_session_folder = Config->get_default_session_parent_dir();
1718 open_session_selector.add_shortcut_folder (default_session_folder);
1720 catch (Glib::Error & e) {
1721 std::cerr << "open_session_selector.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
1724 FileFilter session_filter;
1725 session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
1726 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
1727 open_session_selector.add_filter (session_filter);
1728 open_session_selector.set_filter (session_filter);
1730 int response = open_session_selector.run();
1731 open_session_selector.hide ();
1733 if (response == Gtk::RESPONSE_CANCEL) {
1737 string session_path = open_session_selector.get_filename();
1741 if (session_path.length() > 0) {
1742 if (ARDOUR::find_session (session_path, path, name, isnew) == 0) {
1743 _session_is_new = isnew;
1744 load_session (path, name);
1751 ARDOUR_UI::session_add_mixed_track (const ChanCount& input, const ChanCount& output, RouteGroup* route_group,
1752 uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1754 list<boost::shared_ptr<MidiTrack> > tracks;
1756 if (_session == 0) {
1757 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1762 tracks = _session->new_midi_track (input, output, instrument, ARDOUR::Normal, route_group, how_many, name_template);
1764 if (tracks.size() != how_many) {
1765 error << string_compose(P_("could not create %1 new mixed track", "could not create %1 new mixed tracks", how_many), how_many) << endmsg;
1770 MessageDialog msg (_main_window,
1771 string_compose (_("There are insufficient ports available\n\
1772 to create a new track or bus.\n\
1773 You should save %1, exit and\n\
1774 restart with more ports."), PROGRAM_NAME));
1781 ARDOUR_UI::session_add_midi_route (bool disk, RouteGroup* route_group, uint32_t how_many, const string& name_template, PluginInfoPtr instrument)
1783 ChanCount one_midi_channel;
1784 one_midi_channel.set (DataType::MIDI, 1);
1787 session_add_mixed_track (one_midi_channel, one_midi_channel, route_group, how_many, name_template, instrument);
1792 ARDOUR_UI::session_add_audio_route (
1794 int32_t input_channels,
1795 int32_t output_channels,
1796 ARDOUR::TrackMode mode,
1797 RouteGroup* route_group,
1799 string const & name_template
1802 list<boost::shared_ptr<AudioTrack> > tracks;
1805 if (_session == 0) {
1806 warning << _("You cannot add a track or bus without a session already loaded.") << endmsg;
1812 tracks = _session->new_audio_track (input_channels, output_channels, mode, route_group, how_many, name_template);
1814 if (tracks.size() != how_many) {
1815 error << string_compose (P_("could not create %1 new audio track", "could not create %1 new audio tracks", how_many), how_many)
1821 routes = _session->new_audio_route (input_channels, output_channels, route_group, how_many, name_template);
1823 if (routes.size() != how_many) {
1824 error << string_compose (P_("could not create %1 new audio bus", "could not create %1 new audio busses", how_many), how_many)
1831 MessageDialog msg (_main_window,
1832 string_compose (_("There are insufficient ports available\n\
1833 to create a new track or bus.\n\
1834 You should save %1, exit and\n\
1835 restart with more ports."), PROGRAM_NAME));
1836 pop_back_splash (msg);
1842 ARDOUR_UI::transport_goto_start ()
1845 _session->goto_start();
1847 /* force displayed area in editor to start no matter
1848 what "follow playhead" setting is.
1852 editor->center_screen (_session->current_start_frame ());
1858 ARDOUR_UI::transport_goto_zero ()
1861 _session->request_locate (0);
1863 /* force displayed area in editor to start no matter
1864 what "follow playhead" setting is.
1868 editor->reset_x_origin (0);
1874 ARDOUR_UI::transport_goto_wallclock ()
1876 if (_session && editor) {
1883 localtime_r (&now, &tmnow);
1885 framecnt_t frame_rate = _session->frame_rate();
1887 if (frame_rate == 0) {
1888 /* no frame rate available */
1892 frames = tmnow.tm_hour * (60 * 60 * frame_rate);
1893 frames += tmnow.tm_min * (60 * frame_rate);
1894 frames += tmnow.tm_sec * frame_rate;
1896 _session->request_locate (frames, _session->transport_rolling ());
1898 /* force displayed area in editor to start no matter
1899 what "follow playhead" setting is.
1903 editor->center_screen (frames);
1909 ARDOUR_UI::transport_goto_end ()
1912 framepos_t const frame = _session->current_end_frame();
1913 _session->request_locate (frame);
1915 /* force displayed area in editor to start no matter
1916 what "follow playhead" setting is.
1920 editor->center_screen (frame);
1926 ARDOUR_UI::transport_stop ()
1932 if (_session->is_auditioning()) {
1933 _session->cancel_audition ();
1937 _session->request_stop (false, true);
1940 /** Check if any tracks are record enabled. If none are, record enable all of them.
1941 * @return true if track record-enabled status was changed, false otherwise.
1944 ARDOUR_UI::trx_record_enable_all_tracks ()
1950 boost::shared_ptr<RouteList> rl = _session->get_tracks ();
1951 bool none_record_enabled = true;
1953 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
1954 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1957 if (t->record_enabled()) {
1958 none_record_enabled = false;
1963 if (none_record_enabled) {
1964 _session->set_record_enabled (rl, true, Session::rt_cleanup);
1967 return none_record_enabled;
1971 ARDOUR_UI::transport_record (bool roll)
1974 switch (_session->record_status()) {
1975 case Session::Disabled:
1976 if (_session->ntracks() == 0) {
1977 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."));
1981 if (Profile->get_trx()) {
1982 roll = trx_record_enable_all_tracks ();
1984 _session->maybe_enable_record ();
1989 case Session::Recording:
1991 _session->request_stop();
1993 _session->disable_record (false, true);
1997 case Session::Enabled:
1998 _session->disable_record (false, true);
2004 ARDOUR_UI::transport_roll ()
2010 if (_session->is_auditioning()) {
2015 if (_session->config.get_external_sync()) {
2016 switch (Config->get_sync_source()) {
2020 /* transport controlled by the master */
2026 bool rolling = _session->transport_rolling();
2028 if (_session->get_play_loop()) {
2030 /* If loop playback is not a mode, then we should cancel
2031 it when this action is requested. If it is a mode
2032 we just leave it in place.
2035 if (!Config->get_loop_is_mode()) {
2036 /* XXX it is not possible to just leave seamless loop and keep
2037 playing at present (nov 4th 2009)
2039 if (!Config->get_seamless_loop()) {
2040 /* stop loop playback and stop rolling */
2041 _session->request_play_loop (false, true);
2042 } else if (rolling) {
2043 /* stop loop playback but keep rolling */
2044 _session->request_play_loop (false, false);
2048 } else if (_session->get_play_range () ) {
2049 /* stop playing a range if we currently are */
2050 _session->request_play_range (0, true);
2054 _session->request_transport_speed (1.0f);
2059 ARDOUR_UI::get_smart_mode() const
2061 return ( editor->get_smart_mode() );
2066 ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
2072 if (_session->is_auditioning()) {
2073 _session->cancel_audition ();
2077 if (_session->config.get_external_sync()) {
2078 switch (Config->get_sync_source()) {
2082 /* transport controlled by the master */
2087 bool rolling = _session->transport_rolling();
2088 bool affect_transport = true;
2090 if (rolling && roll_out_of_bounded_mode) {
2091 /* drop out of loop/range playback but leave transport rolling */
2092 if (_session->get_play_loop()) {
2093 if (_session->actively_recording()) {
2095 /* just stop using the loop, then actually stop
2098 _session->request_play_loop (false, affect_transport);
2101 if (Config->get_seamless_loop()) {
2102 /* the disk buffers contain copies of the loop - we can't
2103 just keep playing, so stop the transport. the user
2104 can restart as they wish.
2106 affect_transport = true;
2108 /* disk buffers are normal, so we can keep playing */
2109 affect_transport = false;
2111 _session->request_play_loop (false, affect_transport);
2113 } else if (_session->get_play_range ()) {
2114 affect_transport = false;
2115 _session->request_play_range (0, true);
2119 if (affect_transport) {
2121 _session->request_stop (with_abort, true);
2123 /* the only external sync condition we can be in here
2124 * would be Engine (JACK) sync, in which case we still
2128 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
2129 _session->request_play_range (&editor->get_selection().time, true);
2130 _session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
2132 _session->request_transport_speed (1.0f);
2138 ARDOUR_UI::toggle_session_auto_loop ()
2144 Location * looploc = _session->locations()->auto_loop_location();
2150 if (_session->get_play_loop()) {
2152 /* looping enabled, our job is to disable it */
2154 _session->request_play_loop (false);
2158 /* looping not enabled, our job is to enable it.
2160 loop-is-NOT-mode: this action always starts the transport rolling.
2161 loop-IS-mode: this action simply sets the loop play mechanism, but
2162 does not start transport.
2164 if (Config->get_loop_is_mode()) {
2165 _session->request_play_loop (true, false);
2167 _session->request_play_loop (true, true);
2171 //show the loop markers
2172 looploc->set_hidden (false, this);
2176 ARDOUR_UI::transport_play_selection ()
2182 editor->play_selection ();
2186 ARDOUR_UI::transport_play_preroll ()
2191 editor->play_with_preroll ();
2195 ARDOUR_UI::transport_rewind (int option)
2197 float current_transport_speed;
2200 current_transport_speed = _session->transport_speed();
2202 if (current_transport_speed >= 0.0f) {
2205 _session->request_transport_speed (-1.0f);
2208 _session->request_transport_speed (-4.0f);
2211 _session->request_transport_speed (-0.5f);
2216 _session->request_transport_speed (current_transport_speed * 1.5f);
2222 ARDOUR_UI::transport_forward (int option)
2228 float current_transport_speed = _session->transport_speed();
2230 if (current_transport_speed <= 0.0f) {
2233 _session->request_transport_speed (1.0f);
2236 _session->request_transport_speed (4.0f);
2239 _session->request_transport_speed (0.5f);
2244 _session->request_transport_speed (current_transport_speed * 1.5f);
2249 ARDOUR_UI::toggle_record_enable (uint32_t rid)
2255 boost::shared_ptr<Route> r;
2257 if ((r = _session->route_by_remote_id (rid)) != 0) {
2259 boost::shared_ptr<Track> t;
2261 if ((t = boost::dynamic_pointer_cast<Track>(r)) != 0) {
2262 t->set_record_enabled (!t->record_enabled(), Controllable::UseGroup);
2268 ARDOUR_UI::map_transport_state ()
2271 auto_loop_button.unset_active_state ();
2272 play_selection_button.unset_active_state ();
2273 roll_button.unset_active_state ();
2274 stop_button.set_active_state (Gtkmm2ext::ExplicitActive);
2278 shuttle_box->map_transport_state ();
2280 float sp = _session->transport_speed();
2286 if (_session->get_play_range()) {
2288 play_selection_button.set_active_state (Gtkmm2ext::ExplicitActive);
2289 roll_button.unset_active_state ();
2290 auto_loop_button.unset_active_state ();
2292 } else if (_session->get_play_loop ()) {
2294 auto_loop_button.set_active (true);
2295 play_selection_button.set_active (false);
2296 if (Config->get_loop_is_mode()) {
2297 roll_button.set_active (true);
2299 roll_button.set_active (false);
2304 roll_button.set_active (true);
2305 play_selection_button.set_active (false);
2306 auto_loop_button.set_active (false);
2309 if (UIConfiguration::instance().get_follow_edits() && !_session->config.get_external_sync()) {
2310 /* light up both roll and play-selection if they are joined */
2311 roll_button.set_active (true);
2312 play_selection_button.set_active (true);
2315 stop_button.set_active (false);
2319 stop_button.set_active (true);
2320 roll_button.set_active (false);
2321 play_selection_button.set_active (false);
2322 if (Config->get_loop_is_mode ()) {
2323 auto_loop_button.set_active (_session->get_play_loop());
2325 auto_loop_button.set_active (false);
2327 update_disk_space ();
2332 ARDOUR_UI::blink_handler (bool blink_on)
2334 transport_rec_enable_blink (blink_on);
2335 solo_blink (blink_on);
2336 sync_blink (blink_on);
2337 audition_blink (blink_on);
2338 feedback_blink (blink_on);
2339 error_blink (blink_on);
2343 ARDOUR_UI::update_clocks ()
2345 if (!_session) return;
2347 if (editor && !editor->dragging_playhead()) {
2348 Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
2353 ARDOUR_UI::start_clocking ()
2355 if (UIConfiguration::instance().get_super_rapid_clock_update()) {
2356 clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2358 clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
2363 ARDOUR_UI::stop_clocking ()
2365 clock_signal_connection.disconnect ();
2369 ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
2373 snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
2375 label->set_text (buf);
2376 bar->set_fraction (fraction);
2378 /* process events, redraws, etc. */
2380 while (gtk_events_pending()) {
2381 gtk_main_iteration ();
2384 return true; /* continue with save-as */
2388 ARDOUR_UI::save_session_as ()
2394 if (!save_as_dialog) {
2395 save_as_dialog = new SaveAsDialog;
2398 save_as_dialog->set_name (_session->name());
2400 int response = save_as_dialog->run ();
2402 save_as_dialog->hide ();
2405 case Gtk::RESPONSE_OK:
2414 sa.new_parent_folder = save_as_dialog->new_parent_folder ();
2415 sa.new_name = save_as_dialog->new_name ();
2416 sa.switch_to = save_as_dialog->switch_to();
2417 sa.copy_media = save_as_dialog->copy_media();
2418 sa.copy_external = save_as_dialog->copy_external();
2419 sa.include_media = save_as_dialog->include_media ();
2421 /* Only bother with a progress dialog if we're going to copy
2422 media into the save-as target. Without that choice, this
2423 will be very fast because we're only talking about a few kB's to
2424 perhaps a couple of MB's of data.
2427 ArdourDialog progress_dialog (_("Save As"), true);
2429 if (sa.include_media && sa.copy_media) {
2432 Gtk::ProgressBar progress_bar;
2434 progress_dialog.get_vbox()->pack_start (label);
2435 progress_dialog.get_vbox()->pack_start (progress_bar);
2437 progress_bar.show ();
2439 /* this signal will be emitted from within this, the calling thread,
2440 * after every file is copied. It provides information on percentage
2441 * complete (in terms of total data to copy), the number of files
2442 * copied so far, and the total number to copy.
2447 sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
2449 progress_dialog.show_all ();
2450 progress_dialog.present ();
2453 if (_session->save_as (sa)) {
2455 MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
2459 if (!sa.include_media) {
2460 unload_session (false);
2461 load_session (sa.final_session_folder_name, sa.new_name);
2466 ARDOUR_UI::quick_snapshot_session (bool switch_to_it)
2470 struct tm local_time;
2473 localtime_r (&n, &local_time);
2474 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2476 save_state (timebuf, switch_to_it);
2481 ARDOUR_UI::process_snapshot_session_prompter (ArdourPrompter& prompter, bool switch_to_it)
2485 prompter.get_result (snapname);
2487 bool do_save = (snapname.length() != 0);
2490 char illegal = Session::session_name_is_legal(snapname);
2492 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2493 "snapshot names may not contain a '%1' character"), illegal));
2499 vector<std::string> p;
2500 get_state_files_in_directory (_session->session_directory().root_path(), p);
2501 vector<string> n = get_file_names_no_extension (p);
2503 if (find (n.begin(), n.end(), snapname) != n.end()) {
2505 do_save = overwrite_file_dialog (prompter,
2506 _("Confirm Snapshot Overwrite"),
2507 _("A snapshot already exists with that name. Do you want to overwrite it?"));
2511 save_state (snapname, switch_to_it);
2521 /** Ask the user for the name of a new snapshot and then take it.
2525 ARDOUR_UI::snapshot_session (bool switch_to_it)
2527 ArdourPrompter prompter (true);
2529 prompter.set_name ("Prompter");
2530 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2532 prompter.set_title (_("Save as..."));
2533 prompter.set_prompt (_("New session name"));
2535 prompter.set_title (_("Take Snapshot"));
2536 prompter.set_prompt (_("Name of new snapshot"));
2540 prompter.set_initial_text (_session->snap_name());
2544 struct tm local_time;
2547 localtime_r (&n, &local_time);
2548 strftime (timebuf, sizeof(timebuf), "%FT%H.%M.%S", &local_time);
2549 prompter.set_initial_text (timebuf);
2552 bool finished = false;
2554 switch (prompter.run()) {
2555 case RESPONSE_ACCEPT:
2557 finished = process_snapshot_session_prompter (prompter, switch_to_it);
2568 /** Ask the user for a new session name and then rename the session to it.
2572 ARDOUR_UI::rename_session ()
2578 ArdourPrompter prompter (true);
2581 prompter.set_name ("Prompter");
2582 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2583 prompter.set_title (_("Rename Session"));
2584 prompter.set_prompt (_("New session name"));
2587 switch (prompter.run()) {
2588 case RESPONSE_ACCEPT:
2590 prompter.get_result (name);
2592 bool do_rename = (name.length() != 0);
2595 char illegal = Session::session_name_is_legal (name);
2598 MessageDialog msg (string_compose (_("To ensure compatibility with various systems\n"
2599 "session names may not contain a '%1' character"), illegal));
2604 switch (_session->rename (name)) {
2606 MessageDialog msg (_("That name is already in use by another directory/folder. Please try again."));
2607 msg.set_position (WIN_POS_MOUSE);
2615 MessageDialog msg (_("Renaming this session failed.\nThings could be seriously messed up at this point"));
2616 msg.set_position (WIN_POS_MOUSE);
2632 ARDOUR_UI::save_state (const string & name, bool switch_to_it)
2634 if (!_session || _session->deletion_in_progress()) {
2638 XMLNode* node = new XMLNode (X_("UI"));
2640 WM::Manager::instance().add_state (*node);
2642 node->add_child_nocopy (gui_object_state->get_state());
2644 _session->add_extra_xml (*node);
2646 if (export_video_dialog) {
2647 _session->add_extra_xml (export_video_dialog->get_state());
2650 save_state_canfail (name, switch_to_it);
2654 ARDOUR_UI::save_state_canfail (string name, bool switch_to_it)
2659 if ((ret = _session->save_state (name, false, switch_to_it)) != 0) {
2664 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2669 ARDOUR_UI::primary_clock_value_changed ()
2672 _session->request_locate (primary_clock->current_time ());
2677 ARDOUR_UI::big_clock_value_changed ()
2680 _session->request_locate (big_clock->current_time ());
2685 ARDOUR_UI::secondary_clock_value_changed ()
2688 _session->request_locate (secondary_clock->current_time ());
2693 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
2695 if (_session == 0) {
2699 if (_session->step_editing()) {
2703 Session::RecordState const r = _session->record_status ();
2704 bool const h = _session->have_rec_enabled_track ();
2706 if (r == Session::Enabled || (r == Session::Recording && !h)) {
2708 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2710 rec_button.set_active_state (Gtkmm2ext::Off);
2712 } else if (r == Session::Recording && h) {
2713 rec_button.set_active_state (Gtkmm2ext::ExplicitActive);
2715 rec_button.unset_active_state ();
2720 ARDOUR_UI::process_save_template_prompter (ArdourPrompter& prompter)
2724 prompter.get_result (name);
2726 if (name.length()) {
2727 int failed = _session->save_template (name);
2729 if (failed == -2) { /* file already exists. */
2730 bool overwrite = overwrite_file_dialog (prompter,
2731 _("Confirm Template Overwrite"),
2732 _("A template already exists with that name. Do you want to overwrite it?"));
2735 _session->save_template (name, true);
2747 ARDOUR_UI::save_template ()
2749 ArdourPrompter prompter (true);
2751 if (!check_audioengine(*editor)) {
2755 prompter.set_name (X_("Prompter"));
2756 prompter.set_title (_("Save Template"));
2757 prompter.set_prompt (_("Name for template:"));
2758 prompter.set_initial_text(_session->name() + _("-template"));
2759 prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
2761 bool finished = false;
2763 switch (prompter.run()) {
2764 case RESPONSE_ACCEPT:
2765 finished = process_save_template_prompter (prompter);
2776 ARDOUR_UI::edit_metadata ()
2778 SessionMetadataEditor dialog;
2779 dialog.set_session (_session);
2780 dialog.grab_focus ();
2785 ARDOUR_UI::import_metadata ()
2787 SessionMetadataImporter dialog;
2788 dialog.set_session (_session);
2793 ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path)
2795 std::string str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path);
2797 MessageDialog msg (str,
2799 Gtk::MESSAGE_WARNING,
2800 Gtk::BUTTONS_YES_NO,
2804 msg.set_name (X_("OpenExistingDialog"));
2805 msg.set_title (_("Open Existing Session"));
2806 msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
2807 msg.set_position (Gtk::WIN_POS_CENTER);
2808 pop_back_splash (msg);
2810 switch (msg.run()) {
2819 ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name)
2821 BusProfile bus_profile;
2823 if (nsm || Profile->get_sae()) {
2825 bus_profile.master_out_channels = 2;
2826 bus_profile.input_ac = AutoConnectPhysical;
2827 bus_profile.output_ac = AutoConnectMaster;
2828 bus_profile.requested_physical_in = 0; // use all available
2829 bus_profile.requested_physical_out = 0; // use all available
2833 /* get settings from advanced section of NSD */
2835 if (sd.create_master_bus()) {
2836 bus_profile.master_out_channels = (uint32_t) sd.master_channel_count();
2838 bus_profile.master_out_channels = 0;
2841 if (sd.connect_inputs()) {
2842 bus_profile.input_ac = AutoConnectPhysical;
2844 bus_profile.input_ac = AutoConnectOption (0);
2847 bus_profile.output_ac = AutoConnectOption (0);
2849 if (sd.connect_outputs ()) {
2850 if (sd.connect_outs_to_master()) {
2851 bus_profile.output_ac = AutoConnectMaster;
2852 } else if (sd.connect_outs_to_physical()) {
2853 bus_profile.output_ac = AutoConnectPhysical;
2857 bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count();
2858 bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count();
2861 if (build_session (session_path, session_name, bus_profile)) {
2869 ARDOUR_UI::load_from_application_api (const std::string& path)
2871 ARDOUR_COMMAND_LINE::session_name = path;
2872 /* Cancel SessionDialog if it's visible to make OSX delegates work.
2874 * ARDOUR_UI::starting connects app->ShouldLoad signal and then shows a SessionDialog
2876 * - ShouldLoad does not arrive in time, ARDOUR_COMMAND_LINE::session_name is empty:
2877 * -> ARDOUR_UI::get_session_parameters starts a SessionDialog.
2878 * - ShouldLoad signal arrives, this function is called and sets ARDOUR_COMMAND_LINE::session_name
2879 * -> SessionDialog is not displayed
2882 if (_session_dialog) {
2883 std::string session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2884 std::string session_path = path;
2885 if (Glib::file_test (session_path, Glib::FILE_TEST_IS_REGULAR)) {
2886 session_path = Glib::path_get_dirname (session_path);
2888 // signal the existing dialog in ARDOUR_UI::get_session_parameters()
2889 _session_dialog->set_provided_session (session_name, session_path);
2890 _session_dialog->response (RESPONSE_NONE);
2891 _session_dialog->hide();
2896 if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
2897 /* /path/to/foo => /path/to/foo, foo */
2898 rv = load_session (path, basename_nosuffix (path));
2900 /* /path/to/foo/foo.ardour => /path/to/foo, foo */
2901 rv =load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
2904 // if load_session fails -> pop up SessionDialog.
2906 ARDOUR_COMMAND_LINE::session_name = "";
2908 if (get_session_parameters (true, false)) {
2912 goto_editor_window ();
2916 /** @param quit_on_cancel true if exit() should be called if the user clicks `cancel' in the new session dialog */
2918 ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, string load_template)
2920 string session_name;
2921 string session_path;
2922 string template_name;
2924 bool likely_new = false;
2925 bool cancel_not_quit;
2927 /* deal with any existing DIRTY session now, rather than later. don't
2928 * treat a non-dirty session this way, so that it stays visible
2929 * as we bring up the new session dialog.
2932 if (_session && ARDOUR_UI::instance()->video_timeline) {
2933 ARDOUR_UI::instance()->video_timeline->sync_session_state();
2936 /* if there is already a session, relabel the button
2937 on the SessionDialog so that we don't Quit directly
2939 cancel_not_quit = (_session != 0);
2941 if (_session && _session->dirty()) {
2942 if (unload_session (false)) {
2943 /* unload cancelled by user */
2946 ARDOUR_COMMAND_LINE::session_name = "";
2949 if (!load_template.empty()) {
2950 should_be_new = true;
2951 template_name = load_template;
2954 session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name);
2955 session_path = ARDOUR_COMMAND_LINE::session_name;
2957 if (!session_path.empty()) {
2958 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) {
2959 if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) {
2960 /* session/snapshot file, change path to be dir */
2961 session_path = Glib::path_get_dirname (session_path);
2966 SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit);
2968 _session_dialog = &session_dialog;
2971 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
2973 /* if they named a specific statefile, use it, otherwise they are
2974 just giving a session folder, and we want to use it as is
2975 to find the session.
2978 string::size_type suffix = ARDOUR_COMMAND_LINE::session_name.find (statefile_suffix);
2980 if (suffix != string::npos) {
2981 session_path = Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name);
2982 session_name = ARDOUR_COMMAND_LINE::session_name.substr (0, suffix);
2983 session_name = Glib::path_get_basename (session_name);
2985 session_path = ARDOUR_COMMAND_LINE::session_name;
2986 session_name = Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name);
2991 session_dialog.clear_given ();
2994 if (should_be_new || session_name.empty()) {
2995 /* need the dialog to get info from user */
2997 cerr << "run dialog\n";
2999 switch (session_dialog.run()) {
3000 case RESPONSE_ACCEPT:
3003 /* this is used for async * app->ShouldLoad(). */
3004 continue; // while loop
3007 if (quit_on_cancel) {
3008 // JE - Currently (July 2014) this section can only get reached if the
3009 // user quits from the main 'Session Setup' dialog (i.e. reaching this
3010 // point does NOT indicate an abnormal termination). Therefore, let's
3011 // behave gracefully (i.e. let's do some cleanup) before we call exit()
3013 pthread_cancel_all ();
3021 session_dialog.hide ();
3024 /* if we run the startup dialog again, offer more than just "new session" */
3026 should_be_new = false;
3028 session_name = session_dialog.session_name (likely_new);
3029 session_path = session_dialog.session_folder ();
3035 string::size_type suffix = session_name.find (statefile_suffix);
3037 if (suffix != string::npos) {
3038 session_name = session_name.substr (0, suffix);
3041 /* this shouldn't happen, but we catch it just in case it does */
3043 if (session_name.empty()) {
3047 if (session_dialog.use_session_template()) {
3048 template_name = session_dialog.session_template_name();
3049 _session_is_new = true;
3052 if (session_name[0] == G_DIR_SEPARATOR ||
3053 #ifdef PLATFORM_WINDOWS
3054 (session_name.length() > 3 && session_name[1] == ':' && session_name[2] == G_DIR_SEPARATOR)
3056 (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == G_DIR_SEPARATOR) ||
3057 (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == G_DIR_SEPARATOR)
3062 /* absolute path or cwd-relative path specified for session name: infer session folder
3063 from what was given.
3066 session_path = Glib::path_get_dirname (session_name);
3067 session_name = Glib::path_get_basename (session_name);
3071 session_path = session_dialog.session_folder();
3073 char illegal = Session::session_name_is_legal (session_name);
3076 MessageDialog msg (session_dialog,
3077 string_compose (_("To ensure compatibility with various systems\n"
3078 "session names may not contain a '%1' character"),
3081 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3086 if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
3089 if (likely_new && !nsm) {
3091 std::string existing = Glib::build_filename (session_path, session_name);
3093 if (!ask_about_loading_existing_session (existing)) {
3094 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3099 _session_is_new = false;
3104 pop_back_splash (session_dialog);
3105 MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path));
3107 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3111 char illegal = Session::session_name_is_legal(session_name);
3114 pop_back_splash (session_dialog);
3115 MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n"
3116 "session names may not contain a '%1' character"), illegal));
3118 ARDOUR_COMMAND_LINE::session_name = ""; // cancel that
3122 _session_is_new = true;
3125 if (likely_new && template_name.empty()) {
3127 ret = build_session_from_dialog (session_dialog, session_path, session_name);
3131 ret = load_session (session_path, session_name, template_name);
3134 /* not connected to the AudioEngine, so quit to avoid an infinite loop */
3138 if (!ARDOUR_COMMAND_LINE::immediate_save.empty()) {
3139 _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false);
3143 /* clear this to avoid endless attempts to load the
3147 ARDOUR_COMMAND_LINE::session_name = "";
3151 _session_dialog = NULL;
3157 ARDOUR_UI::close_session()
3159 if (!check_audioengine(*editor)) {
3163 if (unload_session (true)) {
3167 ARDOUR_COMMAND_LINE::session_name = "";
3169 if (get_session_parameters (true, false)) {
3173 goto_editor_window ();
3176 /** @param snap_name Snapshot name (without .ardour suffix).
3177 * @return -2 if the load failed because we are not connected to the AudioEngine.
3180 ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, std::string mix_template)
3182 Session *new_session;
3187 unload_status = unload_session ();
3189 if (unload_status < 0) {
3191 } else if (unload_status > 0) {
3197 session_loaded = false;
3199 loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME));
3202 new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template);
3205 /* this one is special */
3207 catch (AudioEngine::PortRegistrationFailure& err) {
3209 MessageDialog msg (err.what(),
3212 Gtk::BUTTONS_CLOSE);
3214 msg.set_title (_("Port Registration Error"));
3215 msg.set_secondary_text (_("Click the Close button to try again."));
3216 msg.set_position (Gtk::WIN_POS_CENTER);
3217 pop_back_splash (msg);
3220 int response = msg.run ();
3225 case RESPONSE_CANCEL:
3232 catch (SessionException e) {
3233 MessageDialog msg (string_compose(
3234 _("Session \"%1 (snapshot %2)\" did not load successfully: %3"),
3235 path, snap_name, e.what()),
3240 msg.set_title (_("Loading Error"));
3241 msg.set_position (Gtk::WIN_POS_CENTER);
3242 pop_back_splash (msg);
3254 MessageDialog msg (string_compose(
3255 _("Session \"%1 (snapshot %2)\" did not load successfully"),
3261 msg.set_title (_("Loading Error"));
3262 msg.set_position (Gtk::WIN_POS_CENTER);
3263 pop_back_splash (msg);
3275 list<string> const u = new_session->unknown_processors ();
3277 MissingPluginDialog d (_session, u);
3282 if (!new_session->writable()) {
3283 MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."),
3288 msg.set_title (_("Read-only Session"));
3289 msg.set_position (Gtk::WIN_POS_CENTER);
3290 pop_back_splash (msg);
3297 /* Now the session been created, add the transport controls */
3298 new_session->add_controllable(roll_controllable);
3299 new_session->add_controllable(stop_controllable);
3300 new_session->add_controllable(goto_start_controllable);
3301 new_session->add_controllable(goto_end_controllable);
3302 new_session->add_controllable(auto_loop_controllable);
3303 new_session->add_controllable(play_selection_controllable);
3304 new_session->add_controllable(rec_controllable);
3306 set_session (new_session);
3308 session_loaded = true;
3310 goto_editor_window ();
3313 _session->set_clean ();
3316 #ifdef WINDOWS_VST_SUPPORT
3317 fst_stop_threading();
3321 Timers::TimerSuspender t;
3325 #ifdef WINDOWS_VST_SUPPORT
3326 fst_start_threading();
3335 ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, BusProfile& bus_profile)
3337 Session *new_session;
3340 session_loaded = false;
3341 x = unload_session ();
3349 _session_is_new = true;
3352 new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile);
3355 catch (SessionException e) {
3357 MessageDialog msg (string_compose(_("Could not create session in \"%1\": %2"), path, e.what()));
3358 msg.set_title (_("Loading Error"));
3359 msg.set_position (Gtk::WIN_POS_CENTER);
3360 pop_back_splash (msg);
3366 MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
3367 msg.set_title (_("Loading Error"));
3368 msg.set_position (Gtk::WIN_POS_CENTER);
3369 pop_back_splash (msg);
3374 /* Give the new session the default GUI state, if such things exist */
3377 n = Config->instant_xml (X_("Editor"));
3379 n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
3380 new_session->add_instant_xml (*n, false);
3382 n = Config->instant_xml (X_("Mixer"));
3384 new_session->add_instant_xml (*n, false);
3387 /* Put the playhead at 0 and scroll fully left */
3388 n = new_session->instant_xml (X_("Editor"));
3390 n->add_property (X_("playhead"), X_("0"));
3391 n->add_property (X_("left-frame"), X_("0"));
3394 set_session (new_session);
3396 session_loaded = true;
3398 new_session->save_state(new_session->name());
3404 ARDOUR_UI::launch_chat ()
3406 MessageDialog dialog(_("<b>Just ask and wait for an answer.\nIt may take from minutes to hours.</b>"), true);
3408 dialog.set_title (_("About the Chat"));
3409 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."));
3411 switch (dialog.run()) {
3414 open_uri("http://webchat.freenode.net/?channels=ardour-osx");
3415 #elif defined PLATFORM_WINDOWS
3416 open_uri("http://webchat.freenode.net/?channels=ardour-windows");
3418 open_uri("http://webchat.freenode.net/?channels=ardour");
3427 ARDOUR_UI::launch_manual ()
3429 PBD::open_uri (Config->get_tutorial_manual_url());
3433 ARDOUR_UI::launch_reference ()
3435 PBD::open_uri (Config->get_reference_manual_url());
3439 ARDOUR_UI::launch_tracker ()
3441 PBD::open_uri ("http://tracker.ardour.org");
3445 ARDOUR_UI::launch_subscribe ()
3447 PBD::open_uri ("https://community.ardour.org/s/subscribe");
3451 ARDOUR_UI::launch_cheat_sheet ()
3454 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
3456 PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
3461 ARDOUR_UI::launch_website ()
3463 PBD::open_uri ("http://ardour.org");
3467 ARDOUR_UI::launch_website_dev ()
3469 PBD::open_uri ("http://ardour.org/development.html");
3473 ARDOUR_UI::launch_forums ()
3475 PBD::open_uri ("https://community.ardour.org/forums");
3479 ARDOUR_UI::launch_howto_report ()
3481 PBD::open_uri ("http://ardour.org/reporting_bugs");
3485 ARDOUR_UI::loading_message (const std::string& msg)
3487 if (ARDOUR_COMMAND_LINE::no_splash) {
3495 splash->message (msg);
3499 ARDOUR_UI::show_splash ()
3503 splash = new Splash;
3513 ARDOUR_UI::hide_splash ()
3520 ARDOUR_UI::display_cleanup_results (ARDOUR::CleanupReport& rep, const gchar* list_title, const bool msg_delete)
3524 removed = rep.paths.size();
3527 MessageDialog msgd (_main_window,
3528 _("No files were ready for clean-up"),
3532 msgd.set_title (_("Clean-up"));
3533 msgd.set_secondary_text (_("If this seems suprising, \n\
3534 check for any existing snapshots.\n\
3535 These may still include regions that\n\
3536 require some unused files to continue to exist."));
3542 ArdourDialog results (_("Clean-up"), true, false);
3544 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
3545 CleanupResultsModelColumns() {
3549 Gtk::TreeModelColumn<std::string> visible_name;
3550 Gtk::TreeModelColumn<std::string> fullpath;
3554 CleanupResultsModelColumns results_columns;
3555 Glib::RefPtr<Gtk::ListStore> results_model;
3556 Gtk::TreeView results_display;
3558 results_model = ListStore::create (results_columns);
3559 results_display.set_model (results_model);
3560 results_display.append_column (list_title, results_columns.visible_name);
3562 results_display.set_name ("CleanupResultsList");
3563 results_display.set_headers_visible (true);
3564 results_display.set_headers_clickable (false);
3565 results_display.set_reorderable (false);
3567 Gtk::ScrolledWindow list_scroller;
3570 Gtk::HBox dhbox; // the hbox for the image and text
3571 Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox
3572 Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG));
3574 dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
3576 const string dead_directory = _session->session_directory().dead_path();
3579 %1 - number of files removed
3580 %2 - location of "dead"
3581 %3 - size of files affected
3582 %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
3585 const char* bprefix;
3586 double space_adjusted = 0;
3588 if (rep.space < 1000) {
3590 space_adjusted = rep.space;
3591 } else if (rep.space < 1000000) {
3592 bprefix = _("kilo");
3593 space_adjusted = floorf((float)rep.space / 1000.0);
3594 } else if (rep.space < 1000000 * 1000) {
3595 bprefix = _("mega");
3596 space_adjusted = floorf((float)rep.space / (1000.0 * 1000.0));
3598 bprefix = _("giga");
3599 space_adjusted = floorf((float)rep.space / (1000.0 * 1000 * 1000.0));
3603 txt.set_markup (string_compose (P_("\
3604 The following file was deleted from %2,\n\
3605 releasing %3 %4bytes of disk space", "\
3606 The following %1 files were deleted from %2,\n\
3607 releasing %3 %4bytes of disk space", removed),
3608 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3610 txt.set_markup (string_compose (P_("\
3611 The following file was not in use and \n\
3612 has been moved to: %2\n\n\
3613 After a restart of %5\n\n\
3614 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3615 will release an additional %3 %4bytes of disk space.\n", "\
3616 The following %1 files were not in use and \n\
3617 have been moved to: %2\n\n\
3618 After a restart of %5\n\n\
3619 <span face=\"mono\">Session -> Clean-up -> Flush Wastebasket</span>\n\n\
3620 will release an additional %3 %4bytes of disk space.\n", removed),
3621 removed, Gtkmm2ext::markup_escape_text (dead_directory), space_adjusted, bprefix, PROGRAM_NAME));
3624 dhbox.pack_start (*dimage, true, false, 5);
3625 dhbox.pack_start (txt, true, false, 5);
3627 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
3628 TreeModel::Row row = *(results_model->append());
3629 row[results_columns.visible_name] = *i;
3630 row[results_columns.fullpath] = *i;
3633 list_scroller.add (results_display);
3634 list_scroller.set_size_request (-1, 150);
3635 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
3637 dvbox.pack_start (dhbox, true, false, 5);
3638 dvbox.pack_start (list_scroller, true, false, 5);
3639 ddhbox.pack_start (dvbox, true, false, 5);
3641 results.get_vbox()->pack_start (ddhbox, true, false, 5);
3642 results.add_button (Stock::CLOSE, RESPONSE_CLOSE);
3643 results.set_default_response (RESPONSE_CLOSE);
3644 results.set_position (Gtk::WIN_POS_MOUSE);
3646 results_display.show();
3647 list_scroller.show();
3654 //results.get_vbox()->show();
3655 results.set_resizable (false);
3662 ARDOUR_UI::cleanup ()
3664 if (_session == 0) {
3665 /* shouldn't happen: menu item is insensitive */
3670 MessageDialog checker (_("Are you sure you want to clean-up?"),
3672 Gtk::MESSAGE_QUESTION,
3675 checker.set_title (_("Clean-up"));
3677 checker.set_secondary_text(_("Clean-up is a destructive operation.\n\
3678 ALL undo/redo information will be lost if you clean-up.\n\
3679 Clean-up will move all unused files to a \"dead\" location."));
3681 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3682 checker.add_button (_("Clean-up"), RESPONSE_ACCEPT);
3683 checker.set_default_response (RESPONSE_CANCEL);
3685 checker.set_name (_("CleanupDialog"));
3686 checker.set_wmclass (X_("ardour_cleanup"), PROGRAM_NAME);
3687 checker.set_position (Gtk::WIN_POS_MOUSE);
3689 switch (checker.run()) {
3690 case RESPONSE_ACCEPT:
3696 ARDOUR::CleanupReport rep;
3698 editor->prepare_for_cleanup ();
3700 /* do not allow flush until a session is reloaded */
3702 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket"));
3704 act->set_sensitive (false);
3707 if (_session->cleanup_sources (rep)) {
3708 editor->finish_cleanup ();
3712 editor->finish_cleanup ();
3715 display_cleanup_results (rep, _("Cleaned Files"), false);
3719 ARDOUR_UI::flush_trash ()
3721 if (_session == 0) {
3722 /* shouldn't happen: menu item is insensitive */
3726 ARDOUR::CleanupReport rep;
3728 if (_session->cleanup_trash_sources (rep)) {
3732 display_cleanup_results (rep, _("deleted file"), true);
3736 ARDOUR_UI::cleanup_peakfiles ()
3738 if (_session == 0) {
3739 /* shouldn't happen: menu item is insensitive */
3743 if (! _session->can_cleanup_peakfiles ()) {
3747 // get all region-views in this session
3749 TrackViewList empty;
3751 editor->get_regions_after(rs, (framepos_t) 0, empty);
3752 std::list<RegionView*> views = rs.by_layer();
3754 // remove displayed audio-region-views waveforms
3755 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3756 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3757 if (!arv) { continue ; }
3758 arv->delete_waves();
3761 // cleanup peak files:
3762 // - stop pending peakfile threads
3763 // - close peakfiles if any
3764 // - remove peak dir in session
3765 // - setup peakfiles (background thread)
3766 _session->cleanup_peakfiles ();
3768 // re-add waves to ARV
3769 for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
3770 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
3771 if (!arv) { continue ; }
3772 arv->create_waves();
3777 ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
3779 uint32_t order_hint = UINT32_MAX;
3781 if (editor->get_selection().tracks.empty()) {
3786 we want the new routes to have their order keys set starting from
3787 the highest order key in the selection + 1 (if available).
3790 if (place == AddRouteDialog::AfterSelection) {
3791 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
3793 order_hint = rtav->route()->order_key();
3796 } else if (place == AddRouteDialog::BeforeSelection) {
3797 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
3799 order_hint = rtav->route()->order_key();
3801 } else if (place == AddRouteDialog::First) {
3804 /* leave order_hint at UINT32_MAX */
3807 if (order_hint == UINT32_MAX) {
3808 /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
3809 * not setting an order hint will place new routes last.
3814 _session->set_order_hint (order_hint);
3816 /* create a gap in the existing route order keys to accomodate new routes.*/
3817 boost::shared_ptr <RouteList> rd = _session->get_routes();
3818 for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
3819 boost::shared_ptr<Route> rt (*ri);
3821 if (rt->is_monitor()) {
3825 if (rt->order_key () >= order_hint) {
3826 rt->set_order_key (rt->order_key () + add_route_dialog->count());
3832 ARDOUR_UI::start_duplicate_routes ()
3834 if (!duplicate_routes_dialog) {
3835 duplicate_routes_dialog = new DuplicateRouteDialog;
3838 if (duplicate_routes_dialog->restart (_session)) {
3842 duplicate_routes_dialog->present ();
3846 ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
3854 if (add_route_dialog->is_visible()) {
3855 /* we're already doing this */
3859 ResponseType r = (ResponseType) add_route_dialog->run ();
3861 add_route_dialog->hide();
3864 case RESPONSE_ACCEPT:
3871 if ((count = add_route_dialog->count()) <= 0) {
3875 setup_order_hint(add_route_dialog->insert_at());
3877 string template_path = add_route_dialog->track_template();
3878 DisplaySuspender ds;
3880 if (!template_path.empty()) {
3881 if (add_route_dialog->name_template_is_default()) {
3882 _session->new_route_from_template (count, template_path, string());
3884 _session->new_route_from_template (count, template_path, add_route_dialog->name_template());
3889 ChanCount input_chan= add_route_dialog->channels ();
3890 ChanCount output_chan;
3891 string name_template = add_route_dialog->name_template ();
3892 PluginInfoPtr instrument = add_route_dialog->requested_instrument ();
3893 RouteGroup* route_group = add_route_dialog->route_group ();
3894 AutoConnectOption oac = Config->get_output_auto_connect();
3896 if (oac & AutoConnectMaster) {
3897 output_chan.set (DataType::AUDIO, (_session->master_out() ? _session->master_out()->n_inputs().n_audio() : input_chan.n_audio()));
3898 output_chan.set (DataType::MIDI, 0);
3900 output_chan = input_chan;
3903 /* XXX do something with name template */
3905 switch (add_route_dialog->type_wanted()) {
3906 case AddRouteDialog::AudioTrack:
3907 session_add_audio_track (input_chan.n_audio(), output_chan.n_audio(), add_route_dialog->mode(), route_group, count, name_template);
3909 case AddRouteDialog::MidiTrack:
3910 session_add_midi_track (route_group, count, name_template, instrument);
3912 case AddRouteDialog::MixedTrack:
3913 session_add_mixed_track (input_chan, output_chan, route_group, count, name_template, instrument);
3915 case AddRouteDialog::AudioBus:
3916 session_add_audio_bus (input_chan.n_audio(), output_chan.n_audio(), route_group, count, name_template);
3922 ARDOUR_UI::stop_video_server (bool ask_confirm)
3924 if (!video_server_process && ask_confirm) {
3925 warning << string_compose (_("Video-Server was not launched by %1. The request to stop it is ignored."), PROGRAM_NAME) << endmsg;
3927 if (video_server_process) {
3929 ArdourDialog confirm (_("Stop Video-Server"), true);
3930 Label m (_("Do you really want to stop the Video Server?"));
3931 confirm.get_vbox()->pack_start (m, true, true);
3932 confirm.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
3933 confirm.add_button (_("Yes, Stop It"), Gtk::RESPONSE_ACCEPT);
3934 confirm.show_all ();
3935 if (confirm.run() == RESPONSE_CANCEL) {
3939 delete video_server_process;
3940 video_server_process =0;
3945 ARDOUR_UI::start_video_server_menu (Gtk::Window* float_window)
3947 ARDOUR_UI::start_video_server( float_window, true);
3951 ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg)
3957 if (ARDOUR_UI::instance()->video_timeline->check_server()) {
3958 if (video_server_process) {
3959 popup_error(_("The Video Server is already started."));
3961 popup_error(_("An external Video Server is configured and can be reached. Not starting a new instance."));
3967 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
3969 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
3971 VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
3973 video_server_dialog->set_transient_for (*float_window);
3976 if (!Config->get_show_video_server_dialog() && firsttime < 2) {
3977 video_server_dialog->hide();
3979 ResponseType r = (ResponseType) video_server_dialog->run ();
3980 video_server_dialog->hide();
3981 if (r != RESPONSE_ACCEPT) { return false; }
3982 if (video_server_dialog->show_again()) {
3983 Config->set_show_video_server_dialog(false);
3987 std::string icsd_exec = video_server_dialog->get_exec_path();
3988 std::string icsd_docroot = video_server_dialog->get_docroot();
3989 if (icsd_docroot.empty()) {
3990 #ifndef PLATFORM_WINDOWS
3991 icsd_docroot = X_("/");
3993 icsd_docroot = X_("C:\\");
3998 if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
3999 warning << _("Specified docroot is not an existing directory.") << endmsg;
4002 #ifndef PLATFORM_WINDOWS
4003 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4004 || (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 ) {
4005 warning << _("Given Video Server is not an executable file.") << endmsg;
4009 if ( (g_lstat (icsd_exec.c_str(), &sb) != 0)
4010 || (sb.st_mode & (S_IXUSR)) == 0 ) {
4011 warning << _("Given Video Server is not an executable file.") << endmsg;
4017 argp=(char**) calloc(9,sizeof(char*));
4018 argp[0] = strdup(icsd_exec.c_str());
4019 argp[1] = strdup("-P");
4020 argp[2] = (char*) calloc(16,sizeof(char)); snprintf(argp[2], 16, "%s", video_server_dialog->get_listenaddr().c_str());
4021 argp[3] = strdup("-p");
4022 argp[4] = (char*) calloc(6,sizeof(char)); snprintf(argp[4], 6, "%i", video_server_dialog->get_listenport());
4023 argp[5] = strdup("-C");
4024 argp[6] = (char*) calloc(6,sizeof(char)); snprintf(argp[6], 6, "%i", video_server_dialog->get_cachesize());
4025 argp[7] = strdup(icsd_docroot.c_str());
4027 stop_video_server();
4029 if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
4030 Config->set_video_advanced_setup(false);
4032 std::ostringstream osstream;
4033 osstream << "http://127.0.0.1:" << video_server_dialog->get_listenport() << "/";
4034 Config->set_video_server_url(osstream.str());
4035 Config->set_video_server_docroot(icsd_docroot);
4036 Config->set_video_advanced_setup(true);
4039 if (video_server_process) {
4040 delete video_server_process;
4043 video_server_process = new ARDOUR::SystemExec(icsd_exec, argp);
4044 if (video_server_process->start()) {
4045 warning << _("Cannot launch the video-server") << endmsg;
4048 int timeout = 120; // 6 sec
4049 while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
4050 Glib::usleep (50000);
4052 if (--timeout <= 0 || !video_server_process->is_running()) break;
4055 warning << _("Video-server was started but does not respond to requests...") << endmsg;
4057 if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) {
4058 delete video_server_process;
4059 video_server_process = 0;
4067 ARDOUR_UI::add_video (Gtk::Window* float_window)
4073 if (!start_video_server(float_window, false)) {
4074 warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
4079 add_video_dialog->set_transient_for (*float_window);
4082 if (add_video_dialog->is_visible()) {
4083 /* we're already doing this */
4087 ResponseType r = (ResponseType) add_video_dialog->run ();
4088 add_video_dialog->hide();
4089 if (r != RESPONSE_ACCEPT) { return; }
4091 bool local_file, orig_local_file;
4092 std::string path = add_video_dialog->file_name(local_file);
4094 std::string orig_path = path;
4095 orig_local_file = local_file;
4097 bool auto_set_session_fps = add_video_dialog->auto_set_session_fps();
4099 if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) {
4100 warning << string_compose(_("could not open %1"), path) << endmsg;
4103 if (!local_file && path.length() == 0) {
4104 warning << _("no video-file selected") << endmsg;
4108 std::string audio_from_video;
4109 bool detect_ltc = false;
4111 switch (add_video_dialog->import_option()) {
4112 case VTL_IMPORT_TRANSCODE:
4114 TranscodeVideoDialog *transcode_video_dialog;
4115 transcode_video_dialog = new TranscodeVideoDialog (_session, path);
4116 ResponseType r = (ResponseType) transcode_video_dialog->run ();
4117 transcode_video_dialog->hide();
4118 if (r != RESPONSE_ACCEPT) {
4119 delete transcode_video_dialog;
4123 audio_from_video = transcode_video_dialog->get_audiofile();
4125 if (!audio_from_video.empty() && transcode_video_dialog->detect_ltc()) {
4128 else if (!audio_from_video.empty()) {
4129 editor->embed_audio_from_video(
4131 video_timeline->get_offset(),
4132 (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO)
4135 switch (transcode_video_dialog->import_option()) {
4136 case VTL_IMPORT_TRANSCODED:
4137 path = transcode_video_dialog->get_filename();
4140 case VTL_IMPORT_REFERENCE:
4143 delete transcode_video_dialog;
4146 delete transcode_video_dialog;
4150 case VTL_IMPORT_NONE:
4154 /* strip _session->session_directory().video_path() from video file if possible */
4155 if (local_file && !path.compare(0, _session->session_directory().video_path().size(), _session->session_directory().video_path())) {
4156 path=path.substr(_session->session_directory().video_path().size());
4157 if (path.at(0) == G_DIR_SEPARATOR) {
4158 path=path.substr(1);
4162 video_timeline->set_update_session_fps(auto_set_session_fps);
4164 if (video_timeline->video_file_info(path, local_file)) {
4165 XMLNode* node = new XMLNode(X_("Videotimeline"));
4166 node->add_property (X_("Filename"), path);
4167 node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0"));
4168 node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0"));
4169 if (orig_local_file) {
4170 node->add_property (X_("OriginalVideoFile"), orig_path);
4172 node->remove_property (X_("OriginalVideoFile"));
4174 _session->add_extra_xml (*node);
4175 _session->set_dirty ();
4177 if (!audio_from_video.empty() && detect_ltc) {
4178 std::vector<LTCFileReader::LTCMap> ltc_seq;
4181 /* TODO ask user about TV standard (LTC alignment if any) */
4182 LTCFileReader ltcr (audio_from_video, video_timeline->get_video_file_fps());
4183 /* TODO ASK user which channel: 0 .. ltcr->channels() - 1 */
4185 ltc_seq = ltcr.read_ltc (/*channel*/ 0, /*max LTC frames to decode*/ 15);
4187 /* TODO seek near end of file, and read LTC until end.
4188 * if it fails to find any LTC frames, scan complete file
4190 * calculate drift of LTC compared to video-duration,
4191 * ask user for reference (timecode from start/mid/end)
4194 // LTCFileReader will have written error messages
4197 ::g_unlink(audio_from_video.c_str());
4199 if (ltc_seq.size() == 0) {
4200 PBD::error << _("No LTC detected, video will not be aligned.") << endmsg;
4202 /* the very first TC in the file is somteimes not aligned properly */
4203 int i = ltc_seq.size() -1;
4204 ARDOUR::frameoffset_t video_start_offset =
4205 _session->nominal_frame_rate() * (ltc_seq[i].timecode_sec - ltc_seq[i].framepos_sec);
4206 PBD::info << string_compose (_("Align video-start to %1 [samples]"), video_start_offset) << endmsg;
4207 video_timeline->set_offset(video_start_offset);
4211 _session->maybe_update_session_range(
4212 std::max(video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
4213 std::max(video_timeline->get_offset() + video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0));
4216 if (add_video_dialog->launch_xjadeo() && local_file) {
4217 editor->set_xjadeo_sensitive(true);
4218 editor->toggle_xjadeo_proc(1);
4220 editor->toggle_xjadeo_proc(0);
4222 editor->toggle_ruler_video(true);
4227 ARDOUR_UI::remove_video ()
4229 video_timeline->close_session();
4230 editor->toggle_ruler_video(false);
4233 video_timeline->set_offset_locked(false);
4234 video_timeline->set_offset(0);
4236 /* delete session state */
4237 XMLNode* node = new XMLNode(X_("Videotimeline"));
4238 _session->add_extra_xml(*node);
4239 node = new XMLNode(X_("Videomonitor"));
4240 _session->add_extra_xml(*node);
4241 node = new XMLNode(X_("Videoexport"));
4242 _session->add_extra_xml(*node);
4243 stop_video_server();
4247 ARDOUR_UI::flush_videotimeline_cache (bool localcacheonly)
4249 if (localcacheonly) {
4250 video_timeline->vmon_update();
4252 video_timeline->flush_cache();
4254 editor->queue_visual_videotimeline_update();
4258 ARDOUR_UI::export_video (bool range)
4260 if (ARDOUR::Config->get_show_video_export_info()) {
4261 ExportVideoInfobox infobox (_session);
4262 Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
4263 if (infobox.show_again()) {
4264 ARDOUR::Config->set_show_video_export_info(false);
4267 case GTK_RESPONSE_YES:
4268 PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
4274 export_video_dialog->set_session (_session);
4275 export_video_dialog->apply_state(editor->get_selection().time, range);
4276 export_video_dialog->run ();
4277 export_video_dialog->hide ();
4281 ARDOUR_UI::mixer_settings () const
4286 node = _session->instant_xml(X_("Mixer"));
4288 node = Config->instant_xml(X_("Mixer"));
4292 node = new XMLNode (X_("Mixer"));
4299 ARDOUR_UI::editor_settings () const
4304 node = _session->instant_xml(X_("Editor"));
4306 node = Config->instant_xml(X_("Editor"));
4310 if (getenv("ARDOUR_INSTANT_XML_PATH")) {
4311 node = Config->instant_xml(getenv("ARDOUR_INSTANT_XML_PATH"));
4316 node = new XMLNode (X_("Editor"));
4323 ARDOUR_UI::keyboard_settings () const
4327 node = Config->extra_xml(X_("Keyboard"));
4330 node = new XMLNode (X_("Keyboard"));
4337 ARDOUR_UI::create_xrun_marker (framepos_t where)
4340 Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
4341 _session->locations()->add (location);
4346 ARDOUR_UI::halt_on_xrun_message ()
4348 cerr << "HALT on xrun\n";
4349 MessageDialog msg (_main_window, _("Recording was stopped because your system could not keep up."));
4354 ARDOUR_UI::xrun_handler (framepos_t where)
4360 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::xrun_handler, where)
4362 if (_session && Config->get_create_xrun_marker() && _session->actively_recording()) {
4363 create_xrun_marker(where);
4366 if (_session && Config->get_stop_recording_on_xrun() && _session->actively_recording()) {
4367 halt_on_xrun_message ();
4372 ARDOUR_UI::disk_overrun_handler ()
4374 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_overrun_handler)
4376 if (!have_disk_speed_dialog_displayed) {
4377 have_disk_speed_dialog_displayed = true;
4378 MessageDialog* msg = new MessageDialog (_main_window, string_compose (_("\
4379 The disk system on your computer\n\
4380 was not able to keep up with %1.\n\
4382 Specifically, it failed to write data to disk\n\
4383 quickly enough to keep up with recording.\n"), PROGRAM_NAME));
4384 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4390 /* TODO: this is getting elaborate enough to warrant being split into a dedicated class */
4391 static MessageDialog *scan_dlg = NULL;
4392 static ProgressBar *scan_pbar = NULL;
4393 static HBox *scan_tbox = NULL;
4394 static Gtk::Button *scan_timeout_button;
4397 ARDOUR_UI::cancel_plugin_scan ()
4399 PluginManager::instance().cancel_plugin_scan();
4403 ARDOUR_UI::cancel_plugin_timeout ()
4405 PluginManager::instance().cancel_plugin_timeout();
4406 scan_timeout_button->set_sensitive (false);
4410 ARDOUR_UI::plugin_scan_timeout (int timeout)
4412 if (!scan_dlg || !scan_dlg->is_mapped() || !scan_pbar) {
4416 scan_pbar->set_sensitive (false);
4417 scan_timeout_button->set_sensitive (true);
4418 scan_pbar->set_fraction ((float) timeout / (float) Config->get_vst_scan_timeout());
4421 scan_pbar->set_sensitive (false);
4422 scan_timeout_button->set_sensitive (false);
4428 ARDOUR_UI::plugin_scan_dialog (std::string type, std::string plugin, bool can_cancel)
4430 if (type == X_("closeme") && !(scan_dlg && scan_dlg->is_mapped())) {
4434 const bool cancelled = PluginManager::instance().cancelled();
4435 if (type != X_("closeme") && (!UIConfiguration::instance().get_show_plugin_scan_window()) && !_initial_verbose_plugin_scan) {
4436 if (cancelled && scan_dlg->is_mapped()) {
4441 if (cancelled || !can_cancel) {
4446 static Gtk::Button *cancel_button;
4448 scan_dlg = new MessageDialog("", false, MESSAGE_INFO, BUTTONS_NONE); // TODO manage
4449 VBox* vbox = scan_dlg->get_vbox();
4450 vbox->set_size_request(400,-1);
4451 scan_dlg->set_title (_("Scanning for plugins"));
4453 cancel_button = manage(new Gtk::Button(_("Cancel plugin scan")));
4454 cancel_button->set_name ("EditorGTKButton");
4455 cancel_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_scan) );
4456 cancel_button->show();
4458 scan_dlg->get_vbox()->pack_start ( *cancel_button, PACK_SHRINK);
4460 scan_tbox = manage( new HBox() );
4462 scan_timeout_button = manage(new Gtk::Button(_("Stop Timeout")));
4463 scan_timeout_button->set_name ("EditorGTKButton");
4464 scan_timeout_button->signal_clicked().connect ( mem_fun (*this, &ARDOUR_UI::cancel_plugin_timeout) );
4465 scan_timeout_button->show();
4467 scan_pbar = manage(new ProgressBar());
4468 scan_pbar->set_orientation(Gtk::PROGRESS_RIGHT_TO_LEFT);
4469 scan_pbar->set_text(_("Scan Timeout"));
4472 scan_tbox->pack_start (*scan_pbar, PACK_EXPAND_WIDGET, 4);
4473 scan_tbox->pack_start (*scan_timeout_button, PACK_SHRINK, 4);
4475 scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
4478 assert(scan_dlg && scan_tbox && cancel_button);
4480 if (type == X_("closeme")) {
4484 scan_dlg->set_message(type + ": " + Glib::path_get_basename(plugin));
4487 if (!can_cancel || !cancelled) {
4488 scan_timeout_button->set_sensitive(false);
4490 cancel_button->set_sensitive(can_cancel && !cancelled);
4496 ARDOUR_UI::gui_idle_handler ()
4499 /* due to idle calls, gtk_events_pending() may always return true */
4500 while (gtk_events_pending() && --timeout) {
4501 gtk_main_iteration ();
4506 ARDOUR_UI::disk_underrun_handler ()
4508 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::disk_underrun_handler)
4510 if (!have_disk_speed_dialog_displayed) {
4511 have_disk_speed_dialog_displayed = true;
4512 MessageDialog* msg = new MessageDialog (
4513 _main_window, string_compose (_("The disk system on your computer\n\
4514 was not able to keep up with %1.\n\
4516 Specifically, it failed to read data from disk\n\
4517 quickly enough to keep up with playback.\n"), PROGRAM_NAME));
4518 msg->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg));
4524 ARDOUR_UI::disk_speed_dialog_gone (int /*ignored_response*/, MessageDialog* msg)
4526 have_disk_speed_dialog_displayed = false;
4531 ARDOUR_UI::session_dialog (std::string msg)
4533 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::session_dialog, msg)
4537 d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
4544 ARDOUR_UI::pending_state_dialog ()
4546 HBox* hbox = manage (new HBox());
4547 Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG));
4548 ArdourDialog dialog (_("Crash Recovery"), true);
4549 Label message (string_compose (_("\
4550 This session appears to have been in the\n\
4551 middle of recording when %1 or\n\
4552 the computer was shutdown.\n\
4554 %1 can recover any captured audio for\n\
4555 you, or it can ignore it. Please decide\n\
4556 what you would like to do.\n"), PROGRAM_NAME));
4557 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4558 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4559 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4560 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4561 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
4562 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
4563 dialog.set_default_response (RESPONSE_ACCEPT);
4564 dialog.set_position (WIN_POS_CENTER);
4569 switch (dialog.run ()) {
4570 case RESPONSE_ACCEPT:
4578 ARDOUR_UI::sr_mismatch_dialog (framecnt_t desired, framecnt_t actual)
4580 HBox* hbox = new HBox();
4581 Image* image = new Image (Stock::DIALOG_WARNING, ICON_SIZE_DIALOG);
4582 ArdourDialog dialog (_("Sample Rate Mismatch"), true);
4583 Label message (string_compose (_("\
4584 This session was created with a sample rate of %1 Hz, but\n\
4585 %2 is currently running at %3 Hz. If you load this session,\n\
4586 audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual));
4588 image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
4589 hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
4590 hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
4591 dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
4592 dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
4593 dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
4594 dialog.set_default_response (RESPONSE_ACCEPT);
4595 dialog.set_position (WIN_POS_CENTER);
4600 switch (dialog.run()) {
4601 case RESPONSE_ACCEPT:
4611 ARDOUR_UI::use_config ()
4613 XMLNode* node = Config->extra_xml (X_("TransportControllables"));
4615 set_transport_controllable_state (*node);
4620 ARDOUR_UI::update_transport_clocks (framepos_t pos)
4622 if (UIConfiguration::instance().get_primary_clock_delta_edit_cursor()) {
4623 primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4625 primary_clock->set (pos);
4628 if (UIConfiguration::instance().get_secondary_clock_delta_edit_cursor()) {
4629 secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
4631 secondary_clock->set (pos);
4634 if (big_clock_window) {
4635 big_clock->set (pos);
4637 ARDOUR_UI::instance()->video_timeline->manual_seek_video_monitor(pos);
4641 ARDOUR_UI::step_edit_status_change (bool yn)
4643 // XXX should really store pre-step edit status of things
4644 // we make insensitive
4647 rec_button.set_active_state (Gtkmm2ext::ImplicitActive);
4648 rec_button.set_sensitive (false);
4650 rec_button.unset_active_state ();;
4651 rec_button.set_sensitive (true);
4656 ARDOUR_UI::record_state_changed ()
4658 ENSURE_GUI_THREAD (*this, &ARDOUR_UI::record_state_changed);
4660 if (!_session || !big_clock_window) {
4661 /* why bother - the clock isn't visible */
4665 if (_session->record_status () == Session::Recording && _session->have_rec_enabled_track ()) {
4666 big_clock->set_active (true);
4668 big_clock->set_active (false);
4673 ARDOUR_UI::first_idle ()
4676 _session->allow_auto_play (true);
4680 editor->first_idle();
4683 Keyboard::set_can_save_keybindings (true);
4688 ARDOUR_UI::store_clock_modes ()
4690 XMLNode* node = new XMLNode(X_("ClockModes"));
4692 for (vector<AudioClock*>::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) {
4693 XMLNode* child = new XMLNode (X_("Clock"));
4695 child->add_property (X_("name"), (*x)->name());
4696 child->add_property (X_("mode"), enum_2_string ((*x)->mode()));
4697 child->add_property (X_("on"), ((*x)->off() ? X_("no") : X_("yes")));
4699 node->add_child_nocopy (*child);
4702 _session->add_extra_xml (*node);
4703 _session->set_dirty ();
4706 ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp)
4707 : Controllable (name), ui (u), type(tp)
4713 ARDOUR_UI::TransportControllable::set_value (double val, PBD::Controllable::GroupControlDisposition /*group_override*/)
4716 /* do nothing: these are radio-style actions */
4720 const char *action = 0;
4724 action = X_("Roll");
4727 action = X_("Stop");
4730 action = X_("GotoStart");
4733 action = X_("GotoEnd");
4736 action = X_("Loop");
4739 action = X_("PlaySelection");
4742 action = X_("Record");
4752 Glib::RefPtr<Action> act = ActionManager::get_action ("Transport", action);
4760 ARDOUR_UI::TransportControllable::get_value (void) const
4787 ARDOUR_UI::setup_profile ()
4789 if (gdk_screen_width() < 1200 || getenv ("ARDOUR_NARROW_SCREEN")) {
4790 Profile->set_small_screen ();
4793 if (g_getenv ("ARDOUR_SAE")) {
4794 Profile->set_sae ();
4795 Profile->set_single_package ();
4798 if (g_getenv ("TRX")) {
4799 Profile->set_trx ();
4802 if (g_getenv ("MIXBUS")) {
4803 Profile->set_mixbus ();
4808 ARDOUR_UI::missing_file (Session*s, std::string str, DataType type)
4810 MissingFileDialog dialog (s, str, type);
4815 int result = dialog.run ();
4822 return 1; // quit entire session load
4825 result = dialog.get_action ();
4831 ARDOUR_UI::ambiguous_file (std::string file, std::vector<std::string> hits)
4833 AmbiguousFileDialog dialog (file, hits);
4840 return dialog.get_which ();
4843 /** Allocate our thread-local buffers */
4845 ARDOUR_UI::get_process_buffers ()
4847 _process_thread->get_buffers ();
4850 /** Drop our thread-local buffers */
4852 ARDOUR_UI::drop_process_buffers ()
4854 _process_thread->drop_buffers ();
4858 ARDOUR_UI::feedback_detected ()
4860 _feedback_exists = true;
4864 ARDOUR_UI::successful_graph_sort ()
4866 _feedback_exists = false;
4870 ARDOUR_UI::midi_panic ()
4873 _session->midi_panic();
4878 ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_path)
4880 const char* start_big = "<span size=\"x-large\" weight=\"bold\">";
4881 const char* end_big = "</span>";
4882 const char* start_mono = "<tt>";
4883 const char* end_mono = "</tt>";
4885 MessageDialog msg (string_compose (_("%4This is a session from an older version of %3%5\n\n"
4886 "%3 has copied the old session file\n\n%6%1%7\n\nto\n\n%6%2%7\n\n"
4887 "From now on, use the -2000 version with older versions of %3"),
4888 xml_path, backup_path, PROGRAM_NAME,
4890 start_mono, end_mono), true);
4897 ARDOUR_UI::reset_peak_display ()
4899 if (!_session || !_session->master_out() || !editor_meter) return;
4900 editor_meter->clear_meters();
4901 editor_meter_max_peak = -INFINITY;
4902 editor_meter_peak_display.set_active_state ( Gtkmm2ext::Off );
4906 ARDOUR_UI::reset_group_peak_display (RouteGroup* group)
4908 if (!_session || !_session->master_out()) return;
4909 if (group == _session->master_out()->route_group()) {
4910 reset_peak_display ();
4915 ARDOUR_UI::reset_route_peak_display (Route* route)
4917 if (!_session || !_session->master_out()) return;
4918 if (_session->master_out().get() == route) {
4919 reset_peak_display ();
4924 ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate)
4926 audio_midi_setup->set_desired_sample_rate (desired_sample_rate);
4927 audio_midi_setup->set_position (WIN_POS_CENTER);
4932 response = audio_midi_setup->run();
4934 case Gtk::RESPONSE_OK:
4935 if (!AudioEngine::instance()->running()) {
4949 ARDOUR_UI::transport_numpad_timeout ()
4951 _numpad_locate_happening = false;
4952 if (_numpad_timeout_connection.connected() )
4953 _numpad_timeout_connection.disconnect();
4958 ARDOUR_UI::transport_numpad_decimal ()
4960 _numpad_timeout_connection.disconnect();
4962 if (_numpad_locate_happening) {
4963 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
4964 _numpad_locate_happening = false;
4966 _pending_locate_num = 0;
4967 _numpad_locate_happening = true;
4968 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
4973 ARDOUR_UI::transport_numpad_event (int num)
4975 if ( _numpad_locate_happening ) {
4976 _pending_locate_num = _pending_locate_num*10 + num;
4979 case 0: toggle_roll(false, false); break;
4980 case 1: transport_rewind(1); break;
4981 case 2: transport_forward(1); break;
4982 case 3: transport_record(true); break;
4983 case 4: toggle_session_auto_loop(); break;
4984 case 5: transport_record(false); toggle_session_auto_loop(); break;
4985 case 6: toggle_punch(); break;
4986 case 7: toggle_click(); break;
4987 case 8: toggle_auto_return(); break;
4988 case 9: toggle_follow_edits(); break;
4994 ARDOUR_UI::set_flat_buttons ()
4996 CairoWidget::set_flat_buttons( UIConfiguration::instance().get_flat_buttons() );
5000 ARDOUR_UI::audioengine_became_silent ()
5002 MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
5004 Gtk::MESSAGE_WARNING,
5008 msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
5010 Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
5011 Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
5012 Gtk::Button pay_button (_("Pay for a copy (via the web)"));
5013 Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
5014 Gtk::HBox pay_button_box;
5015 Gtk::HBox subscribe_button_box;
5017 pay_button_box.pack_start (pay_button, true, false);
5018 subscribe_button_box.pack_start (subscribe_button, true, false);
5020 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 */
5022 pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
5023 subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
5025 msg.get_vbox()->pack_start (pay_label);
5026 msg.get_vbox()->pack_start (pay_button_box);
5027 msg.get_vbox()->pack_start (subscribe_label);
5028 msg.get_vbox()->pack_start (subscribe_button_box);
5030 msg.get_vbox()->show_all ();
5032 msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
5033 msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
5034 msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
5039 case Gtk::RESPONSE_YES:
5040 AudioEngine::instance()->reset_silence_countdown ();
5043 case Gtk::RESPONSE_NO:
5045 save_state_canfail ("");
5049 case Gtk::RESPONSE_CANCEL:
5051 /* don't reset, save session and exit */
5057 ARDOUR_UI::hide_application ()
5059 Application::instance ()-> hide ();
5063 ARDOUR_UI::setup_toplevel_window (Gtk::Window& window, const string& name, void* owner)
5065 /* icons, titles, WM stuff */
5067 static list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
5069 if (window_icons.empty()) {
5070 Glib::RefPtr<Gdk::Pixbuf> icon;
5071 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
5072 window_icons.push_back (icon);
5074 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
5075 window_icons.push_back (icon);
5077 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
5078 window_icons.push_back (icon);
5080 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
5081 window_icons.push_back (icon);
5085 if (!window_icons.empty()) {
5086 window.set_default_icon_list (window_icons);
5089 Gtkmm2ext::WindowTitle title (Glib::get_application_name());
5091 window.set_title (title.get_string());
5092 window.set_wmclass (string_compose (X_("%1_%1"), downcase (PROGRAM_NAME), downcase (name)), PROGRAM_NAME);
5094 window.set_flags (CAN_FOCUS);
5095 window.add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
5097 window.signal_configure_event().connect (sigc::mem_fun (*this, &ARDOUR_UI::configure_handler));
5098 window.signal_window_state_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::tabbed_window_state_event_handler), owner));
5099 window.signal_key_press_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5100 window.signal_key_release_event().connect (sigc::bind (sigc::mem_fun (*this, &ARDOUR_UI::key_event_handler), &window), false);
5104 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* window)
5108 return key_press_handler (ev, window);
5113 return key_release_handler (ev, window);
5117 ARDOUR_UI::key_press_handler (GdkEventKey* ev, Gtk::Window* event_window)
5119 if (event_window == &_main_window) {
5120 /* find current tab contents */
5122 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5124 /* see if it uses the ardour binding system */
5126 HasBindings* bindable;
5128 if ((bindable = dynamic_cast<HasBindings*> (w)) != 0) {
5129 KeyboardKey k (ev->state, ev->keyval);
5130 return bindable->bindings().activate (k, Bindings::Press);
5132 /* no bindings in current tab, use baroque GTK mechanism */
5133 return key_press_focus_accelerator_handler (_main_window, ev);
5137 /* no window supplied, try our own bindings */
5138 KeyboardKey k (ev->state, ev->keyval);
5139 return _global_bindings.activate (k, Bindings::Press);
5144 ARDOUR_UI::key_release_handler (GdkEventKey* ev, Gtk::Window* event_window)
5146 if (event_window == &_main_window) {
5147 /* find current tab contents */
5149 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
5151 /* see if it uses the ardour binding system */
5153 HasBindings* bindable;
5155 if ((bindable = dynamic_cast<HasBindings*> (w)) != 0) {
5156 KeyboardKey k (ev->state, ev->keyval);
5157 return bindable->bindings().activate (k, Bindings::Release);
5159 /* no bindings in current tab, use baroque GTK mechanism */
5160 return key_press_focus_accelerator_handler (_main_window, ev);
5164 /* no window supplied, try our own bindings */
5165 KeyboardKey k (ev->state, ev->keyval);
5166 return _global_bindings.activate (k, Bindings::Release);
5167 >>>>>>> first compilable version of tabbable design.