X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=ec3f0becea433c5fd8d562c22c33f18a7443c015;hb=4dc1bbff359308ad884c9429d155f772ebb89bc4;hp=250a94baa43b3af2601fed0fb9821c31c1a92286;hpb=bedc7b170eb72f1b9aaaf3872c7160aa1661a4e1;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 250a94baa4..ec3f0becea 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -27,8 +27,6 @@ #include #include -#include - #include #include #include @@ -60,9 +58,8 @@ #include "gtkmm2ext/popup.h" #include "gtkmm2ext/window_title.h" -#include "midi++/manager.h" - #include "ardour/ardour.h" +#include "ardour/audio_backend.h" #include "ardour/audioengine.h" #include "ardour/audiofilesource.h" #include "ardour/automation_watch.h" @@ -155,6 +152,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) /* big clock */ , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false)) + , video_timeline(0) /* start of private members */ @@ -163,6 +161,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , nsm (0) , _was_dirty (false) , _mixer_on_top (false) + , first_time_engine_run (true) /* transport */ @@ -182,6 +181,9 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , solo_alert_button (_("solo")) , feedback_alert_button (_("feedback")) + , editor_meter(0) + , editor_meter_peak_display() + , speaker_config_window (X_("speaker-config"), _("Speaker Configuration")) , theme_manager (X_("theme-manager"), _("Theme Manager")) , key_editor (X_("key-editor"), _("Key Bindings")) @@ -215,6 +217,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) editor = 0; mixer = 0; + meterbridge = 0; editor = 0; engine = 0; _session_is_new = false; @@ -319,7 +322,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) TimeAxisViewItem::set_constant_heights (); - /* load up the UI manager */ + /* Set this up so that our window proxies can register actions */ ActionManager::init (); @@ -373,6 +376,8 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) _process_thread->init (); DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets)); + + attach_to_engine (); } GlobalPortMatrixWindow* @@ -384,48 +389,156 @@ ARDOUR_UI::create_global_port_matrix (ARDOUR::DataType type) return new GlobalPortMatrixWindow (_session, type); } -int -ARDOUR_UI::create_engine () +void +ARDOUR_UI::attach_to_engine () { - // this gets called every time by new_session() + engine = AudioEngine::instance(); - if (engine) { - return 0; + engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context()); + engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context()); + engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context()); + + engine->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); + + ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports); + + /* if there is only one audio/midi backend, and it does not require setup, get our use of it underway + * right here (we need to know the client name and potential session ID + * to do this, which is why this is here, rather than in, say, + * ARDOUR::init(). + */ + + if (!AudioEngine::instance()->setup_required()) { + const AudioBackendInfo* backend = AudioEngine::instance()->available_backends().front(); + AudioEngine::instance()->set_backend (backend->name, ARDOUR_COMMAND_LINE::backend_client_name, ARDOUR_COMMAND_LINE::backend_session_uuid); + AudioEngine::instance()->start (); } +} - loading_message (_("Starting audio engine")); +void +ARDOUR_UI::engine_stopped () +{ + ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped) + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); +} - try { - engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid); +void +ARDOUR_UI::engine_running () +{ + if (first_time_engine_run) { + post_engine(); + first_time_engine_run = false; + } + + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false); - } catch (...) { + Glib::RefPtr action; + const char* action_name = 0; - return -1; + switch (engine->samples_per_cycle()) { + case 32: + action_name = X_("JACKLatency32"); + break; + case 64: + action_name = X_("JACKLatency64"); + break; + case 128: + action_name = X_("JACKLatency128"); + break; + case 512: + action_name = X_("JACKLatency512"); + break; + case 1024: + action_name = X_("JACKLatency1024"); + break; + case 2048: + action_name = X_("JACKLatency2048"); + break; + case 4096: + action_name = X_("JACKLatency4096"); + break; + case 8192: + action_name = X_("JACKLatency8192"); + break; + default: + /* XXX can we do anything useful ? */ + break; } - engine->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context()); - engine->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context()); - engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context()); + if (action_name) { - engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); + action = ActionManager::get_action (X_("JACK"), action_name); - ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports); + if (action) { + Glib::RefPtr ract = Glib::RefPtr::cast_dynamic (action); + ract->set_active (); + } - post_engine (); + update_disk_space (); + update_cpu_load (); + update_sample_rate (engine->sample_rate()); + update_timecode_format (); + } +} - return 0; +void +ARDOUR_UI::engine_halted (const char* reason, bool free_reason) +{ + if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) { + /* we can't rely on the original string continuing to exist when we are called + again in the GUI thread, so make a copy and note that we need to + free it later. + */ + char *copy = strdup (reason); + Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true)); + return; + } + + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); + + update_sample_rate (0); + + string msgstr; + + /* if the reason is a non-empty string, it means that the backend was shutdown + rather than just Ardour. + */ + + if (strlen (reason)) { + msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason); + } else { + msgstr = string_compose (_("\ +JACK has either been shutdown or it\n\ +disconnected %1 because %1\n\ +was not fast enough. Try to restart\n\ +JACK, reconnect and save the session."), PROGRAM_NAME); + } + + MessageDialog msg (*editor, msgstr); + pop_back_splash (msg); + msg.set_keep_above (true); + msg.run (); + + if (free_reason) { + free (const_cast (reason)); + } } void ARDOUR_UI::post_engine () { - /* Things to be done once we create the AudioEngine + /* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine */ ARDOUR::init_post_engine (); _tooltips.enable(); + ActionManager::load_menus (); + if (setup_windows ()) { throw failed_constructor (); } @@ -483,25 +596,9 @@ ARDOUR_UI::post_engine () Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1); #endif - update_disk_space (); - update_cpu_load (); - update_sample_rate (engine->frame_rate()); - update_timecode_format (); - Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context()); boost::function pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1)); Config->map_parameters (pc); - - /* now start and maybe save state */ - - if (do_engine_start () == 0) { - if (_session && _session_is_new) { - /* we need to retain initial visual - settings for a new session - */ - _session->save_state (""); - } - } } ARDOUR_UI::~ARDOUR_UI () @@ -509,6 +606,7 @@ ARDOUR_UI::~ARDOUR_UI () delete keyboard; delete editor; delete mixer; + delete meterbridge; stop_video_server(); } @@ -686,6 +784,7 @@ ARDOUR_UI::startup () { Application* app = Application::instance (); char *nsm_url; + app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish)); app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load)); @@ -813,13 +912,13 @@ ARDOUR_UI::check_memory_locking () "runs out of memory. \n\n" "You can view the memory limit with 'ulimit -l', " "and it is normally controlled by %2"), - PROGRAM_NAME).c_str(), + PROGRAM_NAME, #ifdef __FreeBSD__ - X_("/etc/login.conf") + X_("/etc/login.conf") #else - X_(" /etc/security/limits.conf") + X_(" /etc/security/limits.conf") #endif - ); + ).c_str()); msg.set_default_response (RESPONSE_OK); @@ -895,11 +994,11 @@ If you still wish to quit, please use the\n\n\ second_connection.disconnect (); point_one_second_connection.disconnect (); - point_oh_five_second_connection.disconnect (); - point_zero_one_second_connection.disconnect(); + point_zero_something_second_connection.disconnect(); } delete ARDOUR_UI::instance()->video_timeline; + ARDOUR_UI::instance()->video_timeline = NULL; stop_video_server(); /* Save state before deleting the session, as that causes some @@ -920,7 +1019,8 @@ If you still wish to quit, please use the\n\n\ _session = 0; } - engine->stop (true); + halt_connection.disconnect (); + engine->stop (); quit (); } @@ -1025,11 +1125,20 @@ ARDOUR_UI::every_point_one_seconds () } gint -ARDOUR_UI::every_point_zero_one_seconds () +ARDOUR_UI::every_point_zero_something_seconds () { - // august 2007: actual update frequency: 40Hz, not 100Hz + // august 2007: actual update frequency: 25Hz (40ms), not 100Hz SuperRapidScreenUpdate(); /* EMIT_SIGNAL */ + if (editor_meter && Config->get_show_editor_meter()) { + float mpeak = editor_meter->update_meters(); + if (mpeak > editor_meter_max_peak) { + if (mpeak >= Config->get_meter_peak()) { + editor_meter_peak_display.set_name ("meterbridge peakindicator on"); + editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); + } + } + } return TRUE; } @@ -1042,20 +1151,26 @@ ARDOUR_UI::update_sample_rate (framecnt_t) if (!engine->connected()) { - snprintf (buf, sizeof (buf), "%s", _("disconnected")); + snprintf (buf, sizeof (buf), _("Audio: none")); } else { - framecnt_t rate = engine->frame_rate(); + framecnt_t rate = engine->sample_rate(); - if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("JACK: %.1f kHz / %4.1f ms"), - (float) rate/1000.0f, - (engine->frames_per_cycle() / (float) rate) * 1000.0f); + if (rate == 0) { + /* no sample rate available */ + snprintf (buf, sizeof (buf), _("Audio: none")); } else { - snprintf (buf, sizeof (buf), _("JACK: %" PRId64 " kHz / %4.1f ms"), - rate/1000, - (engine->frames_per_cycle() / (float) rate) * 1000.0f); + + if (fmod (rate, 1000.0) != 0.0) { + snprintf (buf, sizeof (buf), _("Audio: %.1f kHz / %4.1f ms"), + (float) rate / 1000.0f, + (engine->usecs_per_cycle() / 1000.0f)); + } else { + snprintf (buf, sizeof (buf), _("Audio: %" PRId64 " kHz / %4.1f ms"), + rate/1000, + (engine->usecs_per_cycle() / 1000.0f)); + } } } @@ -1179,6 +1294,11 @@ ARDOUR_UI::update_disk_space() char buf[64]; framecnt_t fr = _session->frame_rate(); + if (fr == 0) { + /* skip update - no SR available */ + return; + } + if (!opt_frames) { /* Available space is unknown */ snprintf (buf, sizeof (buf), "%s", _("Disk: Unknown")); @@ -1485,7 +1605,14 @@ ARDOUR_UI::open_session () open_session_selector->set_current_folder(Config->get_default_session_parent_dir()); } - open_session_selector->add_shortcut_folder (Config->get_default_session_parent_dir()); + string default_session_folder = Config->get_default_session_parent_dir(); + try { + /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */ + open_session_selector->add_shortcut_folder (default_session_folder); + } + catch (Glib::Error & e) { + std::cerr << "open_session_selector->add_shortcut_folder (" << default_session_folder << ") threw Glib::Error " << e.what() << std::endl; + } FileFilter session_filter; session_filter.add_pattern ("*.ardour"); @@ -1653,10 +1780,17 @@ ARDOUR_UI::transport_goto_wallclock () time (&now); localtime_r (&now, &tmnow); + + int frame_rate = _session->frame_rate(); + + if (frame_rate == 0) { + /* no frame rate available */ + return; + } - frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate()); - frames += tmnow.tm_min * (60 * _session->frame_rate()); - frames += tmnow.tm_sec * _session->frame_rate(); + frames = tmnow.tm_hour * (60 * 60 * frame_rate); + frames += tmnow.tm_min * (60 * frame_rate); + frames += tmnow.tm_sec * frame_rate; _session->request_locate (frames, _session->transport_rolling ()); @@ -2016,127 +2150,6 @@ ARDOUR_UI::map_transport_state () } } -void -ARDOUR_UI::engine_stopped () -{ - ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped) - ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); - ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); -} - -void -ARDOUR_UI::engine_running () -{ - ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_running) - ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true); - ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false); - - Glib::RefPtr action; - const char* action_name = 0; - - switch (engine->frames_per_cycle()) { - case 32: - action_name = X_("JACKLatency32"); - break; - case 64: - action_name = X_("JACKLatency64"); - break; - case 128: - action_name = X_("JACKLatency128"); - break; - case 512: - action_name = X_("JACKLatency512"); - break; - case 1024: - action_name = X_("JACKLatency1024"); - break; - case 2048: - action_name = X_("JACKLatency2048"); - break; - case 4096: - action_name = X_("JACKLatency4096"); - break; - case 8192: - action_name = X_("JACKLatency8192"); - break; - default: - /* XXX can we do anything useful ? */ - break; - } - - if (action_name) { - - action = ActionManager::get_action (X_("JACK"), action_name); - - if (action) { - Glib::RefPtr ract = Glib::RefPtr::cast_dynamic (action); - ract->set_active (); - } - } -} - -void -ARDOUR_UI::engine_halted (const char* reason, bool free_reason) -{ - if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) { - /* we can't rely on the original string continuing to exist when we are called - again in the GUI thread, so make a copy and note that we need to - free it later. - */ - char *copy = strdup (reason); - Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true)); - return; - } - - ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); - ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); - - update_sample_rate (0); - - string msgstr; - - /* if the reason is a non-empty string, it means that the backend was shutdown - rather than just Ardour. - */ - - if (strlen (reason)) { - msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason); - } else { - msgstr = string_compose (_("\ -JACK has either been shutdown or it\n\ -disconnected %1 because %1\n\ -was not fast enough. Try to restart\n\ -JACK, reconnect and save the session."), PROGRAM_NAME); - } - - MessageDialog msg (*editor, msgstr); - pop_back_splash (msg); - msg.set_keep_above (true); - msg.run (); - - if (free_reason) { - free (const_cast (reason)); - } -} - -int32_t -ARDOUR_UI::do_engine_start () -{ - try { - engine->start(); - } - - catch (...) { - engine->stop (); - error << _("Unable to start the session running") - << endmsg; - unload_session (); - return -2; - } - - return 0; -} - void ARDOUR_UI::update_clocks () { @@ -2687,10 +2700,6 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } } - if (create_engine ()) { - break; - } - if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { if (likely_new && !nsm) { @@ -3423,9 +3432,28 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) Config->set_video_advanced_setup(true); } + if (video_server_process) { + delete video_server_process; + } + video_server_process = new SystemExec(icsd_exec, argp); - video_server_process->start(); - sleep(1); + if (video_server_process->start()) { + warning << _("Cannot launch the video-server") << endmsg; + continue; + } + int timeout = 120; // 6 sec + while (!ARDOUR_UI::instance()->video_timeline->check_server()) { + usleep (50000); + if (--timeout <= 0 || !video_server_process->is_running()) break; + } + if (timeout <= 0) { + warning << _("Video-server was started but does not respond to requests...") << endmsg; + } else { + if (!ARDOUR_UI::instance()->video_timeline->check_server_docroot()) { + delete video_server_process; + video_server_process = 0; + } + } } return true; } @@ -3455,8 +3483,12 @@ ARDOUR_UI::add_video (Gtk::Window* float_window) add_video_dialog->hide(); if (r != RESPONSE_ACCEPT) { return; } - bool local_file; + bool local_file, orig_local_file; std::string path = add_video_dialog->file_name(local_file); + + std::string orig_path = path; + orig_local_file = local_file; + bool auto_set_session_fps = add_video_dialog->auto_set_session_fps(); if (local_file && !Glib::file_test(path, Glib::FILE_TEST_EXISTS)) { @@ -3480,7 +3512,10 @@ ARDOUR_UI::add_video (Gtk::Window* float_window) return; } if (!transcode_video_dialog->get_audiofile().empty()) { - editor->embed_audio_from_video(transcode_video_dialog->get_audiofile()); + editor->embed_audio_from_video( + transcode_video_dialog->get_audiofile(), + video_timeline->get_offset() + ); } switch (transcode_video_dialog->import_option()) { case VTL_IMPORT_TRANSCODED: @@ -3515,6 +3550,11 @@ ARDOUR_UI::add_video (Gtk::Window* float_window) node->add_property (X_("Filename"), path); node->add_property (X_("AutoFPS"), auto_set_session_fps?X_("1"):X_("0")); node->add_property (X_("LocalFile"), local_file?X_("1"):X_("0")); + if (orig_local_file) { + node->add_property (X_("OriginalVideoFile"), orig_path); + } else { + node->remove_property (X_("OriginalVideoFile")); + } _session->add_extra_xml (*node); _session->set_dirty (); @@ -3539,6 +3579,10 @@ ARDOUR_UI::remove_video () video_timeline->close_session(); editor->toggle_ruler_video(false); + /* reset state */ + video_timeline->set_offset_locked(false); + video_timeline->set_offset(0); + /* delete session state */ XMLNode* node = new XMLNode(X_("Videotimeline")); _session->add_extra_xml(*node); @@ -3779,9 +3823,16 @@ void ARDOUR_UI::disconnect_from_jack () { if (engine) { - if (engine->disconnect_from_jack ()) { + /* drop connection to AudioEngine::Halted so that we don't act + * as if the engine unexpectedly shut down + */ + halt_connection.disconnect (); + + if (engine->stop ()) { MessageDialog msg (*editor, _("Could not disconnect from JACK")); msg.run (); + } else { + engine->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); } update_sample_rate (0); @@ -3792,7 +3843,7 @@ void ARDOUR_UI::reconnect_to_jack () { if (engine) { - if (engine->reconnect_to_jack ()) { + if (engine->start ()) { MessageDialog msg (*editor, _("Could not reconnect to JACK")); msg.run (); } @@ -4076,3 +4127,32 @@ ARDOUR_UI::session_format_mismatch (std::string xml_path, std::string backup_pat msg.run (); } + + +void +ARDOUR_UI::reset_peak_display () +{ + if (!_session || !_session->master_out() || !editor_meter) return; + editor_meter->clear_meters(); + editor_meter_max_peak = -INFINITY; + editor_meter_peak_display.set_name ("meterbridge peakindicator"); + editor_meter_peak_display.set_elements((ArdourButton::Element) (ArdourButton::Edge|ArdourButton::Body)); +} + +void +ARDOUR_UI::reset_group_peak_display (RouteGroup* group) +{ + if (!_session || !_session->master_out()) return; + if (group == _session->master_out()->route_group()) { + reset_peak_display (); + } +} + +void +ARDOUR_UI::reset_route_peak_display (Route* route) +{ + if (!_session || !_session->master_out()) return; + if (_session->master_out().get() == route) { + reset_peak_display (); + } +}