X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=8487d1d547a9ede6869d61fb288787e70a42d3c0;hb=f45ec9f87ba140560038fd36d31c1324e779548f;hp=a7034a167786a473a9b4a071b566642ef2446a41;hpb=6b480bb2f7d16288b5fa0d35f827ad32f88a6978;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index a7034a1677..8487d1d547 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -58,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" @@ -102,6 +101,7 @@ typedef uint64_t microseconds_t; #include "missing_plugin_dialog.h" #include "mixer_ui.h" #include "mouse_cursors.h" +#include "nsm.h" #include "opts.h" #include "pingback.h" #include "processor_box.h" @@ -110,6 +110,7 @@ typedef uint64_t microseconds_t; #include "rc_option_editor.h" #include "route_time_axis.h" #include "route_params_ui.h" +#include "session_dialog.h" #include "session_metadata_dialog.h" #include "session_option_editor.h" #include "shuttle_control.h" @@ -153,14 +154,14 @@ 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 */ - , _startup (0) - , engine (0) , nsm (0) , _was_dirty (false) , _mixer_on_top (false) + , first_time_engine_run (true) /* transport */ @@ -180,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")) @@ -188,6 +192,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , about (X_("about"), _("About")) , location_ui (X_("locations"), _("Locations")) , route_params (X_("inspector"), _("Tracks and Busses")) + , audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup")) , session_option_editor (X_("session-options-editor"), _("Properties"), boost::bind (&ARDOUR_UI::create_session_option_editor, this)) , add_video_dialog (X_("add-video"), _("Add Tracks/Busses"), boost::bind (&ARDOUR_UI::create_add_video_dialog, this)) , bundle_manager (X_("bundle-manager"), _("Bundle Manager"), boost::bind (&ARDOUR_UI::create_bundle_manager, this)) @@ -199,7 +204,6 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) , _status_bar_visibility (X_("status-bar")) , _feedback_exists (false) - { Gtkmm2ext::init(localedir); @@ -213,8 +217,8 @@ 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; session_selector_window = 0; last_key_press_time = 0; @@ -262,6 +266,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) ARDOUR::Session::AskAboutPendingState.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::pending_state_dialog, this)); + /* handle Audio/MIDI setup when session requires it */ + + ARDOUR::Session::AudioEngineSetupRequired.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::do_audio_midi_setup, this, _1)); + /* handle sr mismatch with a dialog (PROBLEM: needs to return a value and thus cannot be x-thread) */ ARDOUR::Session::AskAboutSampleRateMismatch.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::sr_mismatch_dialog, this, _1, _2)); @@ -285,21 +293,10 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) /* lets get this party started */ - try { - if (ARDOUR::init (ARDOUR_COMMAND_LINE::use_vst, ARDOUR_COMMAND_LINE::try_hw_optimization, localedir)) { - throw failed_constructor (); - } - - setup_gtk_ardour_enums (); - setup_profile (); - - SessionEvent::create_per_thread_pool ("GUI", 512); + setup_gtk_ardour_enums (); + setup_profile (); - } catch (failed_constructor& err) { - error << string_compose (_("could not initialize %1."), PROGRAM_NAME) << endmsg; - // pass it on up - throw; - } + SessionEvent::create_per_thread_pool ("GUI", 512); /* we like keyboards */ @@ -351,6 +348,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) WM::Manager::instance().register_window (&add_route_dialog); WM::Manager::instance().register_window (&add_video_dialog); WM::Manager::instance().register_window (&route_params); + WM::Manager::instance().register_window (&audio_midi_setup); WM::Manager::instance().register_window (&bundle_manager); WM::Manager::instance().register_window (&location_ui); WM::Manager::instance().register_window (&big_clock_window); @@ -364,13 +362,12 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir) (void) theme_manager.get (true); - starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup)); - stopping.connect (sigc::mem_fun(*this, &ARDOUR_UI::shutdown)); - _process_thread = new ProcessThread (); _process_thread->init (); DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets)); + + attach_to_engine (); } GlobalPortMatrixWindow* @@ -382,45 +379,92 @@ 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() - - if (engine) { - return 0; - } - - loading_message (_("Starting audio engine")); + AudioEngine::instance()->Running.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_running, this), gui_context()); + ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports); +} - try { - engine = new ARDOUR::AudioEngine (ARDOUR_COMMAND_LINE::jack_client_name, ARDOUR_COMMAND_LINE::jack_session_uuid); +void +ARDOUR_UI::engine_stopped () +{ + ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped) + ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true); +} - } catch (...) { +void +ARDOUR_UI::engine_running () +{ + if (first_time_engine_run) { + post_engine(); + first_time_engine_run = false; + } + + update_disk_space (); + update_cpu_load (); + update_sample_rate (AudioEngine::instance()->sample_rate()); + update_timecode_format (); +} - return -1; +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; } - 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()); + ActionManager::set_sensitive (ActionManager::engine_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::engine_opposite_sensitive_actions, true); - engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); + update_sample_rate (0); - ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports); + string msgstr; - post_engine (); + /* if the reason is a non-empty string, it means that the backend was shutdown + rather than just Ardour. + */ - return 0; + if (strlen (reason)) { + msgstr = string_compose (_("The audio backend was shutdown because:\n\n%1"), reason); + } else { + msgstr = string_compose (_("\ +The audio backend has either been shutdown or it\n\ +disconnected %1 because %1\n\ +was not fast enough. Try to restart\n\ +the audio backend 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 (); + + /* connect to important signals */ + + AudioEngine::instance()->Stopped.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_stopped, this), gui_context()); + AudioEngine::instance()->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context()); + AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); _tooltips.enable(); @@ -483,32 +527,21 @@ 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 () { + if (ui_config->dirty()) { + ui_config->save_state(); + } + delete keyboard; delete editor; delete mixer; + delete meterbridge; stop_video_server(); } @@ -681,11 +714,13 @@ ARDOUR_UI::check_announcements () #endif } -void -ARDOUR_UI::startup () +int +ARDOUR_UI::starting () { Application* app = Application::instance (); - char *nsm_url; + const char *nsm_url; + bool brand_new_user = ArdourStartup::required (); + app->ShouldQuit.connect (sigc::mem_fun (*this, &ARDOUR_UI::queue_finish)); app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::idle_load)); @@ -695,9 +730,17 @@ ARDOUR_UI::startup () app->ready (); - nsm_url = getenv ("NSM_URL"); + /* we need to create this early because it may need to set the + * audio backend end up. + */ + + try { + audio_midi_setup.get (true); + } catch (...) { + return -1; + } - if (nsm_url) { + if ((nsm_url = g_getenv ("NSM_URL")) != 0) { nsm = new NSM_Client; if (!nsm->init (nsm_url)) { nsm->announce (PROGRAM_NAME, ":dirty:", "ardour3"); @@ -707,19 +750,33 @@ ARDOUR_UI::startup () for ( i = 0; i < 5000; ++i) { nsm->check (); usleep (i); - if (nsm->is_active()) + if (nsm->is_active()) { break; + } + } + if (i == 5000) { + error << _("NSM server did not announce itself") << endmsg; + return -1; } // wait for open command from nsm server for ( i = 0; i < 5000; ++i) { nsm->check (); usleep (1000); - if (nsm->client_id ()) + if (nsm->client_id ()) { break; + } + } + + if (i == 5000) { + error << _("NSM: no client ID provided") << endmsg; + return -1; } if (_session && nsm) { _session->set_nsm_state( nsm->is_active() ); + } else { + error << _("NSM: no session created") << endmsg; + return -1; } // nsm requires these actions disabled @@ -738,15 +795,35 @@ ARDOUR_UI::startup () } } - } - else { + } else { delete nsm; nsm = 0; + error << _("NSM: initialization failed") << endmsg; + return -1; } - } - else if (get_session_parameters (true, ARDOUR_COMMAND_LINE::new_session, ARDOUR_COMMAND_LINE::load_template)) { - exit (1); + } else { + + if (brand_new_user) { + ArdourStartup s; + s.present (); + main().run(); + s.hide (); + switch (s.response ()) { + case Gtk::RESPONSE_OK: + break; + default: + return -1; + } + } + + /* go get a session */ + + const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user); + + if (get_session_parameters (false, new_session_required, ARDOUR_COMMAND_LINE::load_template)) { + return -1; + } } use_config (); @@ -761,13 +838,7 @@ ARDOUR_UI::startup () _status_bar_visibility.update (); BootMessage (string_compose (_("%1 is ready for use"), PROGRAM_NAME)); -} - -void -ARDOUR_UI::no_memory_warning () -{ - XMLNode node (X_("no-memory-warning")); - Config->add_instant_xml (node); + return 0; } void @@ -780,7 +851,7 @@ ARDOUR_UI::check_memory_locking () XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning")); - if (engine->is_realtime() && memory_warning_node == 0) { + if (AudioEngine::instance()->is_realtime() && memory_warning_node == 0) { struct rlimit limits; int64_t ram; @@ -826,9 +897,6 @@ ARDOUR_UI::check_memory_locking () VBox* vbox = msg.get_vbox(); HBox hbox; CheckButton cb (_("Do not show this window again")); - - cb.signal_toggled().connect (sigc::mem_fun (*this, &ARDOUR_UI::no_memory_warning)); - hbox.pack_start (cb, true, false); vbox->pack_start (hbox); cb.show(); @@ -839,6 +907,11 @@ ARDOUR_UI::check_memory_locking () editor->ensure_float (msg); msg.run (); + + if (cb.get_active()) { + XMLNode node (X_("no-memory-warning")); + Config->add_instant_xml (node); + } } } } @@ -895,11 +968,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 +993,8 @@ If you still wish to quit, please use the\n\n\ _session = 0; } - engine->stop (true); + halt_connection.disconnect (); + AudioEngine::instance()->stop (); quit (); } @@ -1025,11 +1099,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; } @@ -1040,25 +1123,30 @@ ARDOUR_UI::update_sample_rate (framecnt_t) ENSURE_GUI_THREAD (*this, &ARDOUR_UI::update_sample_rate, ignored) - if (!engine->connected()) { + if (!AudioEngine::instance()->connected()) { - snprintf (buf, sizeof (buf), "%s", _("disconnected")); + snprintf (buf, sizeof (buf), _("Audio: none")); } else { - framecnt_t rate = engine->frame_rate(); + framecnt_t rate = AudioEngine::instance()->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, + (AudioEngine::instance()->usecs_per_cycle() / 1000.0f)); + } else { + snprintf (buf, sizeof (buf), _("Audio: %" PRId64 " kHz / %4.1f ms"), + rate/1000, + (AudioEngine::instance()->usecs_per_cycle() / 1000.0f)); + } } } - sample_rate_label.set_markup (buf); } @@ -1125,7 +1213,7 @@ ARDOUR_UI::update_cpu_load () should also be changed. */ - float const c = engine->get_cpu_load (); + float const c = AudioEngine::instance()->get_dsp_load (); snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), c >= 90 ? X_("red") : X_("green"), c); cpu_load_label.set_markup (buf); } @@ -1179,6 +1267,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")); @@ -1441,20 +1534,16 @@ ARDOUR_UI::open_recent_session () bool ARDOUR_UI::check_audioengine () { - if (engine) { - if (!engine->connected()) { - MessageDialog msg (string_compose ( - _("%1 is not connected to JACK\n" - "You cannot open or close sessions in this condition"), - PROGRAM_NAME)); - pop_back_splash (msg); - msg.run (); - return false; - } - return true; - } else { + if (!AudioEngine::instance()->connected()) { + MessageDialog msg (string_compose ( + _("%1 is not connected to any audio backend.\n" + "You cannot open or close sessions in this condition"), + PROGRAM_NAME)); + pop_back_splash (msg); + msg.run (); return false; } + return true; } void @@ -1485,7 +1574,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 +1749,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 ()); @@ -1747,7 +1850,7 @@ ARDOUR_UI::transport_roll () #if 0 if (_session->config.get_external_sync()) { switch (Config->get_sync_source()) { - case JACK: + case Engine: break; default: /* transport controlled by the master */ @@ -1797,7 +1900,7 @@ ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode) if (_session->config.get_external_sync()) { switch (Config->get_sync_source()) { - case JACK: + case Engine: break; default: /* transport controlled by the master */ @@ -2016,127 +2119,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 () { @@ -2208,8 +2190,13 @@ ARDOUR_UI::snapshot_session (bool switch_to_it) prompter.set_name ("Prompter"); prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); - prompter.set_title (_("Take Snapshot")); - prompter.set_prompt (_("Name of new snapshot")); + if (switch_to_it) { + prompter.set_title (_("Save as...")); + prompter.set_prompt (_("New session name")); + } else { + prompter.set_title (_("Take Snapshot")); + prompter.set_prompt (_("Name of new snapshot")); + } if (!switch_to_it) { char timebuf[128]; @@ -2490,7 +2477,7 @@ ARDOUR_UI::ask_about_loading_existing_session (const std::string& session_path) } int -ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::string& session_name) +ARDOUR_UI::build_session_from_dialog (SessionDialog& sd, const std::string& session_path, const std::string& session_name) { BusProfile bus_profile; @@ -2506,13 +2493,13 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s /* get settings from advanced section of NSD */ - if (_startup->create_master_bus()) { - bus_profile.master_out_channels = (uint32_t) _startup->master_channel_count(); + if (sd.create_master_bus()) { + bus_profile.master_out_channels = (uint32_t) sd.master_channel_count(); } else { bus_profile.master_out_channels = 0; } - if (_startup->connect_inputs()) { + if (sd.connect_inputs()) { bus_profile.input_ac = AutoConnectPhysical; } else { bus_profile.input_ac = AutoConnectOption (0); @@ -2520,16 +2507,16 @@ ARDOUR_UI::build_session_from_nsd (const std::string& session_path, const std::s bus_profile.output_ac = AutoConnectOption (0); - if (_startup->connect_outputs ()) { - if (_startup->connect_outs_to_master()) { + if (sd.connect_outputs ()) { + if (sd.connect_outs_to_master()) { bus_profile.output_ac = AutoConnectMaster; - } else if (_startup->connect_outs_to_physical()) { + } else if (sd.connect_outs_to_physical()) { bus_profile.output_ac = AutoConnectPhysical; } } - bus_profile.requested_physical_in = (uint32_t) _startup->input_limit_count(); - bus_profile.requested_physical_out = (uint32_t) _startup->output_limit_count(); + bus_profile.requested_physical_in = (uint32_t) sd.input_limit_count(); + bus_profile.requested_physical_out = (uint32_t) sd.output_limit_count(); } if (build_session (session_path, session_name, bus_profile)) { @@ -2565,6 +2552,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri string template_name; int ret = -1; bool likely_new = false; + bool cancel_not_quit; /* deal with any existing DIRTY session now, rather than later. don't * treat a non-dirty session this way, so that it stays visible @@ -2575,6 +2563,11 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri ARDOUR_UI::instance()->video_timeline->sync_session_state(); } + /* if there is already a session, relabel the button + on the SessionDialog so that we don't Quit directly + */ + cancel_not_quit = (_session != 0); + if (_session && _session->dirty()) { if (unload_session (false)) { /* unload cancelled by user */ @@ -2588,6 +2581,20 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri template_name = load_template; } + session_name = basename_nosuffix (ARDOUR_COMMAND_LINE::session_name); + session_path = ARDOUR_COMMAND_LINE::session_name; + + if (!session_path.empty()) { + if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_EXISTS)) { + if (Glib::file_test (session_path.c_str(), Glib::FILE_TEST_IS_REGULAR)) { + /* session/snapshot file, change path to be dir */ + session_path = Glib::path_get_dirname (session_path); + } + } + } + + SessionDialog session_dialog (should_be_new, session_name, session_path, load_template, cancel_not_quit); + while (ret != 0) { if (!ARDOUR_COMMAND_LINE::session_name.empty()) { @@ -2610,34 +2617,35 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } else { session_path = ""; session_name = ""; - } - - delete _startup; - _startup = new ArdourStartup (should_be_new, session_name, session_path, load_template); - - if (!_startup->ready_without_display()) { - _startup->present (); - main().run(); - _startup->hide (); + session_dialog.clear_given (); } - switch (_startup->response()) { - case RESPONSE_OK: - break; - default: - if (quit_on_cancel) { - exit (1); - } else { - return ret; + if (should_be_new || session_name.empty()) { + /* need the dialog to get info from user */ + + cerr << "run dialog\n"; + + switch (session_dialog.run()) { + case RESPONSE_ACCEPT: + break; + default: + if (quit_on_cancel) { + exit (1); + } else { + return ret; + } } + + session_dialog.hide (); } /* if we run the startup dialog again, offer more than just "new session" */ should_be_new = false; - session_name = _startup->session_name (likely_new); - + session_name = session_dialog.session_name (likely_new); + session_path = session_dialog.session_folder (); + if (nsm) { likely_new = true; } @@ -2654,8 +2662,8 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri continue; } - if (_startup->use_session_template()) { - template_name = _startup->session_template_name(); + if (session_dialog.use_session_template()) { + template_name = session_dialog.session_template_name(); _session_is_new = true; } @@ -2672,12 +2680,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } else { - session_path = _startup->session_folder(); + session_path = session_dialog.session_folder(); char illegal = Session::session_name_is_legal (session_name); if (illegal) { - MessageDialog msg (*_startup, + MessageDialog msg (session_dialog, string_compose (_("To ensure compatibility with various systems\n" "session names may not contain a '%1' character"), illegal)); @@ -2687,12 +2695,9 @@ 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) { std::string existing = Glib::build_filename (session_path, session_name); @@ -2708,12 +2713,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } else { if (!likely_new) { - if (_startup) { - pop_back_splash (*_startup); - } else { - hide_splash (); - } - + pop_back_splash (session_dialog); MessageDialog msg (string_compose (_("There is no existing session at \"%1\""), session_path)); msg.run (); ARDOUR_COMMAND_LINE::session_name = ""; // cancel that @@ -2721,10 +2721,11 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri } char illegal = Session::session_name_is_legal(session_name); + if (illegal) { - pop_back_splash (*_startup); - MessageDialog msg (*_startup, string_compose(_("To ensure compatibility with various systems\n" - "session names may not contain a '%1' character"), illegal)); + pop_back_splash (session_dialog); + MessageDialog msg (session_dialog, string_compose(_("To ensure compatibility with various systems\n" + "session names may not contain a '%1' character"), illegal)); msg.run (); ARDOUR_COMMAND_LINE::session_name = ""; // cancel that continue; @@ -2735,7 +2736,7 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri if (likely_new && template_name.empty()) { - ret = build_session_from_nsd (session_path, session_name); + ret = build_session_from_dialog (session_dialog, session_path, session_name); } else { @@ -2750,6 +2751,12 @@ ARDOUR_UI::get_session_parameters (bool quit_on_cancel, bool should_be_new, stri _session->save_state (ARDOUR_COMMAND_LINE::immediate_save, false); exit (1); } + + /* clear this to avoid endless attempts to load the + same session. + */ + + ARDOUR_COMMAND_LINE::session_name = ""; } } @@ -2786,25 +2793,23 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, int unload_status; int retval = -1; - session_loaded = false; - - if (!check_audioengine()) { - return -2; + if (_session) { + unload_status = unload_session (); + + if (unload_status < 0) { + goto out; + } else if (unload_status > 0) { + retval = 0; + goto out; + } } - unload_status = unload_session (); - - if (unload_status < 0) { - goto out; - } else if (unload_status > 0) { - retval = 0; - goto out; - } + session_loaded = false; loading_message (string_compose (_("Please wait while %1 loads your session"), PROGRAM_NAME)); try { - new_session = new Session (*engine, path, snap_name, 0, mix_template); + new_session = new Session (*AudioEngine::instance(), path, snap_name, 0, mix_template); } /* this one is special */ @@ -2844,22 +2849,12 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, Gtk::MESSAGE_INFO, BUTTONS_OK); + msg.set_keep_above (true); msg.set_title (_("Loading Error")); - msg.set_secondary_text (_("Click the Refresh button to try again.")); - msg.add_button (Stock::REFRESH, 1); msg.set_position (Gtk::WIN_POS_CENTER); pop_back_splash (msg); msg.present (); - - int response = msg.run (); - - switch (response) { - case 1: - break; - default: - exit (1); - } - + (void) msg.run (); msg.hide (); goto out; @@ -2873,6 +2868,22 @@ ARDOUR_UI::load_session (const std::string& path, const std::string& snap_name, } } + if (!new_session->writable()) { + MessageDialog msg (_("This session has been opened in read-only mode.\n\nYou will not be able to record or save."), + true, + Gtk::MESSAGE_INFO, + BUTTONS_OK); + + msg.set_keep_above (true); + msg.set_title (_("Read-only Session")); + msg.set_position (Gtk::WIN_POS_CENTER); + pop_back_splash (msg); + msg.present (); + (void) msg.run (); + msg.hide (); + } + + /* Now the session been created, add the transport controls */ new_session->add_controllable(roll_controllable); new_session->add_controllable(stop_controllable); @@ -2905,12 +2916,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, Session *new_session; int x; - if (!check_audioengine()) { - return -1; - } - session_loaded = false; - x = unload_session (); if (x < 0) { @@ -2922,7 +2928,7 @@ ARDOUR_UI::build_session (const std::string& path, const std::string& snap_name, _session_is_new = true; try { - new_session = new Session (*engine, path, snap_name, &bus_profile); + new_session = new Session (*AudioEngine::instance(), path, snap_name, &bus_profile); } catch (...) { @@ -3234,6 +3240,57 @@ ARDOUR_UI::flush_trash () display_cleanup_results (rep, _("deleted file"), true); } +void +ARDOUR_UI::setup_order_hint () +{ + uint32_t order_hint = 0; + + /* + we want the new routes to have their order keys set starting from + the highest order key in the selection + 1 (if available). + */ + if (add_route_dialog->get_transient_for () == mixer->get_toplevel()) { + for (RouteUISelection::iterator s = mixer->selection().routes.begin(); s != mixer->selection().routes.end(); ++s) { + if ((*s)->route()->order_key() > order_hint) { + order_hint = (*s)->route()->order_key(); + } + } + + if (!mixer->selection().routes.empty()) { + order_hint++; + } + + } else { + for (TrackSelection::iterator s = editor->get_selection().tracks.begin(); s != editor->get_selection().tracks.end(); ++s) { + RouteTimeAxisView* tav = dynamic_cast (*s); + if (tav->route()->order_key() > order_hint) { + order_hint = tav->route()->order_key(); + } + } + + if (!editor->get_selection().tracks.empty()) { + order_hint++; + } + } + + _session->set_order_hint (order_hint); + + /* create a gap in the existing route order keys to accomodate new routes.*/ + + boost::shared_ptr rd = _session->get_routes(); + for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) { + boost::shared_ptr rt (*ri); + + if (rt->is_monitor()) { + continue; + } + + if (rt->order_key () >= order_hint) { + rt->set_order_key (rt->order_key () + add_route_dialog->count()); + } + } +} + void ARDOUR_UI::add_route (Gtk::Window* float_window) { @@ -3249,6 +3306,7 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) } if (float_window) { + add_route_dialog->unset_transient_for (); add_route_dialog->set_transient_for (*float_window); } @@ -3268,6 +3326,8 @@ ARDOUR_UI::add_route (Gtk::Window* float_window) return; } + setup_order_hint(); + PBD::ScopedConnection idle_connection; if (count > 8) { @@ -3439,6 +3499,11 @@ ARDOUR_UI::start_video_server (Gtk::Window* float_window, bool popup_msg) } 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; @@ -3469,8 +3534,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)) { @@ -3494,7 +3563,11 @@ 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(), + (transcode_video_dialog->import_option() != VTL_IMPORT_NO_VIDEO) + ); } switch (transcode_video_dialog->import_option()) { case VTL_IMPORT_TRANSCODED: @@ -3529,6 +3602,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 (); @@ -3553,14 +3631,16 @@ 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); node = new XMLNode(X_("Videomonitor")); _session->add_extra_xml(*node); stop_video_server(); - - editor->set_close_video_sensitive(false); } void @@ -3726,8 +3806,8 @@ ARDOUR_UI::session_dialog (std::string msg) int ARDOUR_UI::pending_state_dialog () { - HBox* hbox = new HBox(); - Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG); + HBox* hbox = manage (new HBox()); + Image* image = manage (new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG)); ArdourDialog dialog (_("Crash Recovery"), true); Label message (string_compose (_("\ This session appears to have been in the\n\ @@ -3790,31 +3870,43 @@ audio may be played at the wrong sample rate.\n"), desired, PROGRAM_NAME, actual return 1; } - -void -ARDOUR_UI::disconnect_from_jack () +int +ARDOUR_UI::disconnect_from_engine () { - if (engine) { - if (engine->disconnect_from_jack ()) { - MessageDialog msg (*editor, _("Could not disconnect from JACK")); - msg.run (); - } + /* drop connection to AudioEngine::Halted so that we don't act + * as if the engine unexpectedly shut down + */ - update_sample_rate (0); + halt_connection.disconnect (); + + if (AudioEngine::instance()->stop ()) { + MessageDialog msg (*editor, _("Could not disconnect from Audio/MIDI engine")); + msg.run (); + return -1; + } else { + AudioEngine::instance()->Halted.connect_same_thread (halt_connection, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); } + + update_sample_rate (0); + return 0; } -void -ARDOUR_UI::reconnect_to_jack () +int +ARDOUR_UI::reconnect_to_engine () { - if (engine) { - if (engine->reconnect_to_jack ()) { - MessageDialog msg (*editor, _("Could not reconnect to JACK")); + if (AudioEngine::instance()->start ()) { + if (editor) { + MessageDialog msg (*editor, _("Could not reconnect to the Audio/MIDI engine")); + msg.run (); + } else { + MessageDialog msg (_("Could not reconnect to the Audio/MIDI engine")); msg.run (); } - - update_sample_rate (0); + return -1; } + + update_sample_rate (0); + return 0; } void @@ -4092,3 +4184,50 @@ 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 (); + } +} + +int +ARDOUR_UI::do_audio_midi_setup (uint32_t desired_sample_rate) +{ + audio_midi_setup->set_desired_sample_rate (desired_sample_rate); + audio_midi_setup->set_position (WIN_POS_CENTER); + + switch (audio_midi_setup->run()) { + case Gtk::RESPONSE_OK: + return 0; + case Gtk::RESPONSE_APPLY: + return 0; + default: + return -1; + } +} + +