#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"
, nsm (0)
, _was_dirty (false)
, _mixer_on_top (false)
+ , first_time_engine_run (true)
/* transport */
, 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"))
, add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
, about (X_("about"), _("About"))
, location_ui (X_("locations"), _("Locations"))
+ , route_params (X_("inspector"), _("Tracks and Busses"))
, 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))
, big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
, audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
, midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
- , route_params (X_("inspector"), _("Tracks and Busses"), boost::bind (&ARDOUR_UI::create_route_params_window, this))
, error_log_button (_("Errors"))
editor = 0;
mixer = 0;
+ meterbridge = 0;
editor = 0;
engine = 0;
_session_is_new = false;
and its functionality are separate
*/
- if (audio_port_matrix) {
- audio_port_matrix->set_session (_session);
- }
-
- if (midi_port_matrix) {
- midi_port_matrix->set_session (_session);
- }
-
- if (route_params) {
- route_params->set_session (_session);
- }
-
(void) theme_manager.get (true);
starting.connect (sigc::mem_fun(*this, &ARDOUR_UI::startup));
_process_thread->init ();
DPIReset.connect (sigc::mem_fun (*this, &ARDOUR_UI::resize_text_widgets));
+
+ attach_to_engine ();
}
GlobalPortMatrixWindow*
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> 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<RadioAction> ract = Glib::RefPtr<RadioAction>::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<char*> (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 ();
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<void (string)> 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 ()
delete keyboard;
delete editor;
delete mixer;
+ delete meterbridge;
stop_video_server();
}
{
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));
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;
_session = 0;
}
- engine->stop (true);
+ halt_connection.disconnect ();
+ engine->stop ();
quit ();
}
}
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;
}
if (!engine->connected()) {
- snprintf (buf, sizeof (buf), "%s", _("disconnected"));
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
} 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: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
- (float) rate/1000.0f,
- (engine->frames_per_cycle() / (float) rate) * 1000.0f);
+ if (rate == 0) {
+ /* no sample rate available */
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
} else {
- snprintf (buf, sizeof (buf), _("JACK: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
- rate/1000,
- (engine->frames_per_cycle() / (float) rate) * 1000.0f);
+
+ if (fmod (rate, 1000.0) != 0.0) {
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%.1f kHz / %4.1f ms</span>"),
+ (float) rate / 1000.0f,
+ (engine->usecs_per_cycle() / 1000.0f));
+ } else {
+ snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"green\">%" PRId64 " kHz / %4.1f ms</span>"),
+ rate/1000,
+ (engine->usecs_per_cycle() / 1000.0f));
+ }
}
}
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: <span foreground=\"green\">Unknown</span>"));
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");
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 ());
}
}
-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> 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<RadioAction> ract = Glib::RefPtr<RadioAction>::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<char*> (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 ()
{
}
}
- 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) {
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:
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);
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);
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 ();
}
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 ();
+ }
+}