#include <cerrno>
#include <fstream>
+#include <stdarg.h>
+
#ifndef PLATFORM_WINDOWS
#include <sys/resource.h>
#endif
#include "pbd/file_utils.h"
#include "pbd/localtime_r.h"
#include "pbd/pthread_utils.h"
+#include "pbd/replace_all.h"
+#include "pbd/xml++.h"
#include "gtkmm2ext/application.h"
#include "gtkmm2ext/bindings.h"
#ifdef WINDOWS_VST_SUPPORT
#include <fst.h>
#endif
+#ifdef AUDIOUNIT_SUPPORT
+#include "ardour/audio_unit.h"
+#endif
#include "timecode/time.h"
typedef uint64_t microseconds_t;
#include "about.h"
+#include "editing.h"
#include "actions.h"
#include "add_route_dialog.h"
#include "ambiguous_file_dialog.h"
#include "big_clock_window.h"
#include "bundle_manager.h"
#include "engine_dialog.h"
+#include "export_video_dialog.h"
+#include "export_video_infobox.h"
#include "gain_meter.h"
#include "global_port_matrix.h"
#include "gui_object.h"
#include "rc_option_editor.h"
#include "route_time_axis.h"
#include "route_params_ui.h"
+#include "save_as_dialog.h"
#include "session_dialog.h"
#include "session_metadata_dialog.h"
#include "session_option_editor.h"
#include "startup.h"
#include "theme_manager.h"
#include "time_axis_view_item.h"
+#include "timers.h"
#include "utils.h"
#include "video_server_dialog.h"
#include "add_video_dialog.h"
using namespace Gtkmm2ext;
using namespace Gtk;
using namespace std;
+using namespace Editing;
ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
-UIConfiguration *ARDOUR_UI::ui_config = 0;
-sigc::signal<void,bool> ARDOUR_UI::Blink;
-sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
-sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
-sigc::signal<void> ARDOUR_UI::FPSUpdate;
sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
-ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
+float ARDOUR_UI::ui_scale = 1.0;
- : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
-
- , gui_object_state (new GUIObjectState)
+static bool
+ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
+{
+ MessageDialog msg (string_compose (_("%1 %2.x has discovered configuration files from %1 %3.x.\n\n"
+ "Would you like these files to be copied and used for %1 %2.x?\n\n"
+ "(This will require you to restart %1.)"),
+ PROGRAM_NAME, PROGRAM_VERSION, version),
+ false, /* no markup */
+ Gtk::MESSAGE_INFO,
+ Gtk::BUTTONS_YES_NO,
+ true /* modal, though it hardly matters since it is the only window */
+ );
- , primary_clock (new MainClock (X_("primary"), false, X_("transport"), true, true, true, false, true))
- , secondary_clock (new MainClock (X_("secondary"), false, X_("secondary"), true, true, false, false, true))
+ msg.set_default_response (Gtk::RESPONSE_YES);
+ msg.show_all ();
- /* big clock */
+ return (msg.run() == Gtk::RESPONSE_YES);
+}
- , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
- , video_timeline(0)
+static void
+libxml_generic_error_func (void* /* parsing_context*/,
+ const char* msg,
+ ...)
+{
+ va_list ap;
+ char buf[2048];
+
+ va_start (ap, msg);
+ vsnprintf (buf, sizeof (buf), msg, ap);
+ error << buf << endmsg;
+ va_end (ap);
+}
+
+static void
+libxml_structured_error_func (void* /* parsing_context*/,
+ xmlErrorPtr err)
+{
+ string msg = err->message;
+
+ replace_all (msg, "\n", "");
- /* start of private members */
+ error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
+ if (err->int2) {
+ error << ':' << err->int2;
+ }
+ error << endmsg;
+}
+
+ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir, UIConfiguration* uic)
+
+ : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
+ , ui_config (uic->post_gui_init ())
+ , session_loaded (false)
+ , gui_object_state (new GUIObjectState)
+ , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
+ , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
+ , big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
+ , video_timeline(0)
+ , ignore_dual_punch (false)
+ , editor (0)
+ , mixer (0)
, nsm (0)
, _was_dirty (false)
, _mixer_on_top (false)
, first_time_engine_run (true)
- , blink_timeout_tag (-1)
-
- /* transport */
-
, roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
, stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
, goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
, auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
, play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
, rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
-
, auto_return_button (ArdourButton::led_default_elements)
, follow_edits_button (ArdourButton::led_default_elements)
, auto_input_button (ArdourButton::led_default_elements)
-
, auditioning_alert_button (_("Audition"))
, solo_alert_button (_("Solo"))
, feedback_alert_button (_("Feedback"))
-
+ , error_alert_button ( ArdourButton::just_led_default_elements )
, editor_meter(0)
, editor_meter_peak_display()
-
+ , session_selector_window (0)
+ , open_session_selector (0)
+ , _numpad_locate_happening (false)
+ , _session_is_new (false)
+ , last_key_press_time (0)
+ , save_as_dialog (0)
+ , meterbridge (0)
, speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
- , theme_manager (X_("theme-manager"), _("Theme Manager"))
, key_editor (X_("key-editor"), _("Key Bindings"))
, rc_option_editor (X_("rc-options-editor"), _("Preferences"))
, add_route_dialog (X_("add-routes"), _("Add Tracks/Busses"))
, location_ui (X_("locations"), _("Locations"))
, route_params (X_("inspector"), _("Tracks and Busses"))
, audio_midi_setup (X_("audio-midi-setup"), _("Audio/MIDI Setup"))
+ , export_video_dialog (X_("video-export"), _("Video Export Dialog"))
, 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))
-
- , error_log_button (_("Errors"))
-
+ , video_server_process (0)
+ , splash (0)
+ , have_configure_timeout (false)
+ , last_configure_time (0)
+ , last_peak_grab (0)
+ , have_disk_speed_dialog_displayed (false)
, _status_bar_visibility (X_("status-bar"))
, _feedback_exists (false)
+ , _log_not_acknowledged (LogLevelNone)
{
- Gtkmm2ext::init(localedir);
-
- splash = 0;
-
- _numpad_locate_happening = false;
+ Gtkmm2ext::init (localedir);
+ if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
+ MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
+ msg.run ();
+ /* configuration was modified, exit immediately */
+ _exit (0);
+ }
+
if (theArdourUI == 0) {
theArdourUI = this;
}
- ui_config = new UIConfiguration();
+ /* stop libxml from spewing to stdout/stderr */
+ xmlSetGenericErrorFunc (this, libxml_generic_error_func);
+ xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
+
ui_config->ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
ui_config->map_parameters (pc);
- editor = 0;
- mixer = 0;
- meterbridge = 0;
- editor = 0;
- _session_is_new = false;
- session_selector_window = 0;
- last_key_press_time = 0;
- video_server_process = 0;
- open_session_selector = 0;
- have_configure_timeout = false;
- have_disk_speed_dialog_displayed = false;
- session_loaded = false;
- ignore_dual_punch = false;
-
roll_button.set_controllable (roll_controllable);
stop_button.set_controllable (stop_controllable);
goto_start_button.set_controllable (goto_start_controllable);
rec_button.set_name ("transport recenable button");
midi_panic_button.set_name ("transport button");
- last_configure_time= 0;
- last_peak_grab = 0;
-
ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
const XMLNode* ui_xml = Config->extra_xml (X_("UI"));
if (ui_xml) {
- theme_manager.set_state (*ui_xml);
key_editor.set_state (*ui_xml);
rc_option_editor.set_state (*ui_xml);
session_option_editor.set_state (*ui_xml);
big_clock_window.set_state (*ui_xml);
audio_port_matrix.set_state (*ui_xml);
midi_port_matrix.set_state (*ui_xml);
+ export_video_dialog.set_state (*ui_xml);
}
- WM::Manager::instance().register_window (&theme_manager);
WM::Manager::instance().register_window (&key_editor);
WM::Manager::instance().register_window (&rc_option_editor);
WM::Manager::instance().register_window (&session_option_editor);
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 (&export_video_dialog);
WM::Manager::instance().register_window (&bundle_manager);
WM::Manager::instance().register_window (&location_ui);
WM::Manager::instance().register_window (&big_clock_window);
WM::Manager::instance().register_window (&audio_port_matrix);
WM::Manager::instance().register_window (&midi_port_matrix);
- /* We need to instantiate the theme manager because it loads our
- theme files. This should really change so that its window
- and its functionality are separate
- */
-
- (void) theme_manager.get (true);
+ /* Trigger setting up the color scheme and loading the GTK RC file */
+
+ ARDOUR_UI::config()->load_rc_file (false);
_process_thread = new ProcessThread ();
_process_thread->init ();
first_time_engine_run = false;
}
+ if (_session) {
+ _session->reset_xrun_count ();
+ }
update_disk_space ();
update_cpu_load ();
+ update_xrun_count ();
update_sample_rate (AudioEngine::instance()->sample_rate());
update_timecode_format ();
}
free it later.
*/
char *copy = strdup (reason);
- Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
+ Gtkmm2ext::UI::instance()->call_slot (MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
return;
}
MessageDialog msg (*editor, msgstr);
pop_back_splash (msg);
- msg.set_keep_above (true);
msg.run ();
if (free_reason) {
{
/* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
*/
+#ifdef AUDIOUNIT_SUPPORT
+ std::string au_msg;
+ if (AUPluginInfo::au_get_crashlog(au_msg)) {
+ popup_error(_("Audio Unit Plugin Scan Failed. Automatic AU scanning has been disabled. Please see the log window for further details."));
+ error << _("Audio Unit Plugin Scan Failed:") << endmsg;
+ info << au_msg << endmsg;
+ }
+#endif
ARDOUR::init_post_engine ();
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()->BufferSizeChanged.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));
+ AudioEngine::instance()->BecameSilent.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::audioengine_became_silent, this), gui_context());
_tooltips.enable();
exit (0);
}
- blink_timeout_tag = -1;
-
/* this being a GUI and all, we want peakfiles */
AudioFileSource::set_build_peakfiles (true);
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);
+
+ ui_config->map_parameters (pc);
}
}
ARDOUR_UI::~ARDOUR_UI ()
{
- if (ui_config->dirty()) {
- ui_config->save_state();
- }
+ ui_config->save_state();
stop_video_server();
return *node;
}
+void
+ARDOUR_UI::save_session_at_its_request (std::string snapshot_name)
+{
+ if (_session) {
+ _session->save_state (snapshot_name);
+ }
+}
gint
ARDOUR_UI::autosave_session ()
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));
+ app->ShouldLoad.connect (sigc::mem_fun (*this, &ARDOUR_UI::load_from_application_api));
if (ARDOUR_COMMAND_LINE::check_announcements) {
check_announcements ();
if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
nsm = new NSM_Client;
if (!nsm->init (nsm_url)) {
- nsm->announce (PROGRAM_NAME, ":dirty:", "ardour3");
+ /* the ardour executable may have different names:
+ *
+ * waf's obj.target for distro versions: eg ardour4, ardourvst4
+ * Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
+ * argv[0] does not apply since we need the wrapper-script (not the binary itself)
+ *
+ * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
+ */
+ const char *process_name = g_getenv ("ARDOUR_SELF");
+ nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
unsigned int i = 0;
// wait for announce reply from nsm server
}
}
+#ifdef NO_PLUGIN_STATE
+
+ ARDOUR::RecentSessions rs;
+ ARDOUR::read_recent_sessions (rs);
+
+ string path = Glib::build_filename (user_config_directory(), ".iknowaboutfreeversion");
+
+ if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS) && !rs.empty()) {
+
+ /* already used Ardour, have sessions ... warn about plugin state */
+
+ ArdourDialog d (_("Free/Demo Version Warning"), true);
+ Label l;
+ Button b (string_compose (_("Subscribe and support development of %1"), PROGRAM_NAME));
+ CheckButton c (_("Don't warn me about this again"));
+
+ 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"),
+ string_compose (_("This is a free/demo version of %1"), PROGRAM_NAME),
+ _("It will not restore OR save any plugin settings"),
+ _("If you load an existing session with plugin settings\n"
+ "they will not be used and will be lost."),
+ _("To get full access to updates without this limitation\n"
+ "consider becoming a subscriber for a low cost every month.")));
+ l.set_justify (JUSTIFY_CENTER);
+
+ b.signal_clicked().connect (mem_fun(*this, &ARDOUR_UI::launch_subscribe));
+
+ d.get_vbox()->pack_start (l, true, true);
+ d.get_vbox()->pack_start (b, false, false, 12);
+ d.get_vbox()->pack_start (c, false, false, 12);
+
+ d.add_button (_("Quit now"), RESPONSE_CANCEL);
+ d.add_button (string_compose (_("Continue using %1"), PROGRAM_NAME), RESPONSE_OK);
+
+ d.show_all ();
+
+ c.signal_toggled().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (toggle_file_existence), path)));
+
+ if (d.run () != RESPONSE_OK) {
+ _exit (0);
+ }
+ }
+#endif
+
/* go get a session */
const bool new_session_required = (ARDOUR_COMMAND_LINE::new_session || brand_new_user);
second_connection.disconnect ();
point_one_second_connection.disconnect ();
-#ifndef PLATFORM_WINDOWS
point_zero_something_second_connection.disconnect();
-#endif
fps_connection.disconnect();
}
close_all_dialogs ();
if (_session) {
- // _session->set_deletion_in_progress ();
_session->set_clean ();
_session->remove_pending_capture_state ();
delete _session;
prompt_label.show();
dimage->show();
window.show();
- window.set_keep_above (true);
window.present ();
ResponseType r = (ResponseType) window.run();
}
-gint
+void
ARDOUR_UI::every_second ()
{
update_cpu_load ();
+ update_xrun_count ();
update_buffer_load ();
update_disk_space ();
update_timecode_format ();
_was_dirty = false;
}
}
- return TRUE;
}
-gint
+void
ARDOUR_UI::every_point_one_seconds ()
{
- shuttle_box->update_speed_display ();
- RapidScreenUpdate(); /* EMIT_SIGNAL */
- return TRUE;
+ // TODO get rid of this..
+ // ShuttleControl is updated directly via TransportStateChange signal
}
-gint
+void
ARDOUR_UI::every_point_zero_something_seconds ()
{
// august 2007: actual update frequency: 25Hz (40ms), not 100Hz
- SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
- if (editor_meter && Config->get_show_editor_meter()) {
+ if (editor_meter && ARDOUR_UI::config()->get_show_editor_meter()) {
float mpeak = editor_meter->update_meters();
if (mpeak > editor_meter_max_peak) {
- if (mpeak >= Config->get_meter_peak()) {
+ if (mpeak >= ARDOUR_UI::config()->get_meter_peak()) {
editor_meter_peak_display.set_active_state ( Gtkmm2ext::ExplicitActive );
}
}
}
- return TRUE;
-}
-
-gint
-ARDOUR_UI::every_fps ()
-{
- FPSUpdate(); /* EMIT_SIGNAL */
-#ifdef PLATFORM_WINDOWS
- every_point_zero_something_seconds();
-#endif
- return TRUE;
}
void
#endif
}
fps_connection.disconnect();
- fps_connection = Glib::signal_timeout().connect (sigc::mem_fun(*this, &ARDOUR_UI::every_fps), interval);
+ Timers::set_fps_interval (interval);
}
void
if (!AudioEngine::instance()->connected()) {
- snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
+ snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
} else {
if (rate == 0) {
/* no sample rate available */
- snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
+ snprintf (buf, sizeof (buf), "%s", _("Audio: <span foreground=\"red\">none</span>"));
} else {
if (fmod (rate, 1000.0) != 0.0) {
format_label.set_markup (s.str ());
}
+void
+ARDOUR_UI::update_xrun_count ()
+{
+ char buf[64];
+
+ /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
+ should also be changed.
+ */
+
+ if (_session) {
+ const unsigned int x = _session->get_xrun_count ();
+ if (x > 9999) {
+ snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
+ } else {
+ snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
+ }
+ } else {
+ snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
+ }
+ xrun_label.set_markup (buf);
+ set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
+}
+
void
ARDOUR_UI::update_cpu_load ()
{
should also be changed.
*/
- float const c = AudioEngine::instance()->get_dsp_load ();
+ double const c = AudioEngine::instance()->get_dsp_load ();
snprintf (buf, sizeof (buf), _("DSP: <span foreground=\"%s\">%5.1f%%</span>"), c >= 90 ? X_("red") : X_("green"), c);
cpu_load_label.set_markup (buf);
}
snprintf (buf, sizeof (buf), "%s", _("Disk: <span foreground=\"green\">24hrs+</span>"));
} else {
rec_enabled_streams = 0;
- _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams);
+ _session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams, false);
framecnt_t frames = opt_frames.get_value_or (0);
}
FileFilter session_filter;
- session_filter.add_pattern ("*.ardour");
+ session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
open_session_selector->add_filter (session_filter);
open_session_selector->set_filter (session_filter);
void
ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
{
-
if (!_session) {
return;
}
if (rolling) {
_session->request_stop (with_abort, true);
} else {
- if ( Config->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
+ if (ARDOUR_UI::config()->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
_session->request_play_range (&editor->get_selection().time, true);
_session->set_requested_return_frame( editor->get_selection().time.front().start ); //force an auto-return here
}
auto_loop_button.set_active (false);
}
- if (Config->get_follow_edits()) {
+ if (ARDOUR_UI::config()->get_follow_edits()) {
/* light up both roll and play-selection if they are joined */
roll_button.set_active (true);
play_selection_button.set_active (true);
}
}
+void
+ARDOUR_UI::blink_handler (bool blink_on)
+{
+ transport_rec_enable_blink (blink_on);
+ solo_blink (blink_on);
+ sync_blink (blink_on);
+ audition_blink (blink_on);
+ feedback_blink (blink_on);
+ error_blink (blink_on);
+}
+
void
ARDOUR_UI::update_clocks ()
{
- if (!editor || !editor->dragging_playhead()) {
- Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
+ if (!_session) return;
+
+ if (editor && !editor->dragging_playhead()) {
+ Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
}
}
void
ARDOUR_UI::start_clocking ()
{
- if (Config->get_super_rapid_clock_update()) {
- clock_signal_connection = FPSUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
+ if (ui_config->get_super_rapid_clock_update()) {
+ clock_signal_connection = Timers::fps_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
} else {
- clock_signal_connection = RapidScreenUpdate.connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
+ clock_signal_connection = Timers::rapid_connect (sigc::mem_fun(*this, &ARDOUR_UI::update_clocks));
}
}
clock_signal_connection.disconnect ();
}
-gint
-ARDOUR_UI::_blink (void *arg)
+bool
+ARDOUR_UI::save_as_progress_update (float fraction, int64_t cnt, int64_t total, Gtk::Label* label, Gtk::ProgressBar* bar)
{
- ((ARDOUR_UI *) arg)->blink ();
- return TRUE;
-}
+ char buf[256];
-void
-ARDOUR_UI::blink ()
-{
- Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
+ snprintf (buf, sizeof (buf), _("Copied %" PRId64 " of %" PRId64), cnt, total);
+
+ label->set_text (buf);
+ bar->set_fraction (fraction);
+
+ /* process events, redraws, etc. */
+
+ while (gtk_events_pending()) {
+ gtk_main_iteration ();
+ }
+
+ return true; /* continue with save-as */
}
void
-ARDOUR_UI::start_blinking ()
+ARDOUR_UI::save_session_as ()
{
- /* Start the blink signal. Everybody with a blinking widget
- uses Blink to drive the widget's state.
+ if (!_session) {
+ return;
+ }
+
+ if (!save_as_dialog) {
+ save_as_dialog = new SaveAsDialog;
+ } else {
+ save_as_dialog->clear_name ();
+ }
+
+ int response = save_as_dialog->run ();
+
+ save_as_dialog->hide ();
+
+ switch (response) {
+ case Gtk::RESPONSE_OK:
+ break;
+ default:
+ return;
+ }
+
+
+ Session::SaveAs sa;
+
+ sa.new_parent_folder = save_as_dialog->new_parent_folder ();
+ sa.new_name = save_as_dialog->new_name ();
+ sa.switch_to = save_as_dialog->switch_to();
+ sa.copy_media = save_as_dialog->copy_media();
+ sa.copy_external = save_as_dialog->copy_external();
+ sa.include_media = save_as_dialog->include_media ();
+
+ /* Only bother with a progress dialog if we're going to copy
+ media into the save-as target. Without that choice, this
+ will be very fast because we're only talking about a few kB's to
+ perhaps a couple of MB's of data.
*/
+
+ ArdourDialog progress_dialog (_("Save As"), true);
- if (blink_timeout_tag < 0) {
- blink_on = false;
- blink_timeout_tag = g_timeout_add (240, _blink, this);
+ if (sa.include_media && sa.copy_media) {
+
+ Gtk::Label label;
+ Gtk::ProgressBar progress_bar;
+
+ progress_dialog.get_vbox()->pack_start (label);
+ progress_dialog.get_vbox()->pack_start (progress_bar);
+ label.show ();
+ progress_bar.show ();
+
+ /* this signal will be emitted from within this, the calling thread,
+ * after every file is copied. It provides information on percentage
+ * complete (in terms of total data to copy), the number of files
+ * copied so far, and the total number to copy.
+ */
+
+ ScopedConnection c;
+
+ sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
+
+ progress_dialog.show_all ();
+ progress_dialog.present ();
+ }
+
+ if (_session->save_as (sa)) {
+ /* ERROR MESSAGE */
+ MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
+ msg.run ();
}
-}
-void
-ARDOUR_UI::stop_blinking ()
-{
- if (blink_timeout_tag >= 0) {
- g_source_remove (blink_timeout_tag);
- blink_timeout_tag = -1;
+ if (!sa.include_media) {
+ unload_session (false);
+ load_session (sa.final_session_folder_name, sa.new_name);
}
}
-
/** Ask the user for the name of a new snapshot and then take it.
*/
_session->add_extra_xml (*node);
+ if (export_video_dialog) {
+ _session->add_extra_xml (export_video_dialog->get_state());
+ }
+
save_state_canfail (name, switch_to_it);
}
{
SessionMetadataEditor dialog;
dialog.set_session (_session);
- editor->ensure_float (dialog);
+ dialog.grab_focus ();
dialog.run ();
}
{
SessionMetadataImporter dialog;
dialog.set_session (_session);
- editor->ensure_float (dialog);
dialog.run ();
}
msg.set_name (X_("OpenExistingDialog"));
msg.set_title (_("Open Existing Session"));
msg.set_wmclass (X_("existing_session"), PROGRAM_NAME);
- msg.set_position (Gtk::WIN_POS_MOUSE);
+ msg.set_position (Gtk::WIN_POS_CENTER);
pop_back_splash (msg);
switch (msg.run()) {
}
void
-ARDOUR_UI::idle_load (const std::string& path)
+ARDOUR_UI::load_from_application_api (const std::string& path)
{
- if (_session) {
- if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
- /* /path/to/foo => /path/to/foo, foo */
- load_session (path, basename_nosuffix (path));
- } else {
- /* /path/to/foo/foo.ardour => /path/to/foo, foo */
- load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
- }
+ ARDOUR_COMMAND_LINE::session_name = path;
+ if (Glib::file_test (path, Glib::FILE_TEST_IS_DIR)) {
+ /* /path/to/foo => /path/to/foo, foo */
+ load_session (path, basename_nosuffix (path));
} else {
- ARDOUR_COMMAND_LINE::session_name = path;
+ /* /path/to/foo/foo.ardour => /path/to/foo, foo */
+ load_session (Glib::path_get_dirname (path), basename_nosuffix (path));
}
}
Gtk::MESSAGE_INFO,
BUTTONS_OK);
- msg.set_keep_above (true);
msg.set_title (_("Loading Error"));
msg.set_position (Gtk::WIN_POS_CENTER);
pop_back_splash (msg);
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);
XMLNode* n;
n = Config->instant_xml (X_("Editor"));
if (n) {
+ n->remove_nodes_and_delete ("Selection"); // no not apply selection to new sessions.
new_session->add_instant_xml (*n, false);
}
n = Config->instant_xml (X_("Mixer"));
{
#ifdef __APPLE__
open_uri("http://webchat.freenode.net/?channels=ardour-osx");
+#elif defined PLATFORM_WINDOWS
+ open_uri("http://webchat.freenode.net/?channels=ardour-windows");
#else
open_uri("http://webchat.freenode.net/?channels=ardour");
#endif
PBD::open_uri (Config->get_reference_manual_url());
}
+void
+ARDOUR_UI::launch_tracker ()
+{
+ PBD::open_uri ("http://tracker.ardour.org/bug_report_page.php");
+}
+
+void
+ARDOUR_UI::launch_subscribe ()
+{
+ PBD::open_uri ("https://community.ardour.org/s/subscribe");
+}
+
+void
+ARDOUR_UI::launch_cheat_sheet ()
+{
+#ifdef __APPLE__
+ PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheat_sheet_osx.pdf");
+#else
+ PBD::open_uri ("http://manual.ardour.org/files/a3_mnemonic_cheatsheet.pdf");
+#endif
+}
+
+void
+ARDOUR_UI::launch_website ()
+{
+ PBD::open_uri ("http://ardour.org");
+}
+
+void
+ARDOUR_UI::launch_website_dev ()
+{
+ PBD::open_uri ("http://ardour.org/development.html");
+}
+
+void
+ARDOUR_UI::launch_forums ()
+{
+ PBD::open_uri ("https://community.ardour.org/forums");
+}
+
+void
+ARDOUR_UI::launch_howto_report ()
+{
+ PBD::open_uri ("http://ardour.org/reporting_bugs");
+}
+
void
ARDOUR_UI::loading_message (const std::string& msg)
{
}
void
-ARDOUR_UI::setup_order_hint ()
+ARDOUR_UI::setup_order_hint (AddRouteDialog::InsertAt place)
{
- uint32_t order_hint = 0;
+ uint32_t order_hint = UINT32_MAX;
+ if (editor->get_selection().tracks.empty()) {
+ return;
+ }
+
/*
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()) {
+
+ if (place == AddRouteDialog::AfterSelection) {
+ RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.back());
+ if (rtav) {
+ order_hint = rtav->route()->order_key();
order_hint++;
}
-
- } else {
- for (TrackSelection::iterator s = editor->get_selection().tracks.begin(); s != editor->get_selection().tracks.end(); ++s) {
- RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (*s);
- if (tav && tav->route() && tav->route()->order_key() > order_hint) {
- order_hint = tav->route()->order_key();
- }
+ } else if (place == AddRouteDialog::BeforeSelection) {
+ RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView*> (editor->get_selection().tracks.front());
+ if (rtav) {
+ order_hint = rtav->route()->order_key();
}
+ } else if (place == AddRouteDialog::First) {
+ order_hint = 0;
+ } else {
+ /* leave order_hint at UINT32_MAX */
+ }
- if (!editor->get_selection().tracks.empty()) {
- order_hint++;
- }
+ if (order_hint == UINT32_MAX) {
+ /** AddRouteDialog::Last or selection with first/last not a RouteTimeAxisView
+ * not setting an order hint will place new routes last.
+ */
+ return;
}
_session->set_order_hint (order_hint);
/* create a gap in the existing route order keys to accomodate new routes.*/
-
boost::shared_ptr <RouteList> rd = _session->get_routes();
for (RouteList::iterator ri = rd->begin(); ri != rd->end(); ++ri) {
boost::shared_ptr<Route> rt (*ri);
-
+
if (rt->is_monitor()) {
continue;
}
}
void
-ARDOUR_UI::add_route (Gtk::Window* float_window)
+ARDOUR_UI::add_route (Gtk::Window* /* ignored */)
{
int count;
return;
}
- if (float_window) {
- add_route_dialog->unset_transient_for ();
- add_route_dialog->set_transient_for (*float_window);
- }
-
ResponseType r = (ResponseType) add_route_dialog->run ();
add_route_dialog->hide();
return;
}
- setup_order_hint();
+ setup_order_hint(add_route_dialog->insert_at());
string template_path = add_route_dialog->track_template();
DisplaySuspender ds;
int firsttime = 0;
while (!ARDOUR_UI::instance()->video_timeline->check_server()) {
if (firsttime++) {
- warning << _("Could not connect to the Video Server. Start it or configure its access URL in Edit -> Preferences.") << endmsg;
+ warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
}
VideoServerDialog *video_server_dialog = new VideoServerDialog (_session);
if (float_window) {
std::string icsd_exec = video_server_dialog->get_exec_path();
std::string icsd_docroot = video_server_dialog->get_docroot();
- if (icsd_docroot.empty()) {icsd_docroot = X_("/");}
+ if (icsd_docroot.empty()) {
+#ifndef PLATFORM_WINDOWS
+ icsd_docroot = X_("/");
+#else
+ icsd_docroot = X_("C:\\");
+#endif
+ }
GStatBuf sb;
if (g_lstat (icsd_docroot.c_str(), &sb) != 0 || !S_ISDIR(sb.st_mode)) {
argp[8] = 0;
stop_video_server();
- if (icsd_docroot == X_("/")) {
+ if (icsd_docroot == X_("/") || icsd_docroot == X_("C:\\")) {
Config->set_video_advanced_setup(false);
} else {
std::ostringstream osstream;
}
if (!start_video_server(float_window, false)) {
- warning << _("Could not connect to the Video Server. Start it or configure its access URL in Edit -> Preferences.") << endmsg;
+ warning << _("Could not connect to the Video Server. Start it or configure its access URL in Preferences.") << endmsg;
return;
}
_session->add_extra_xml(*node);
node = new XMLNode(X_("Videomonitor"));
_session->add_extra_xml(*node);
+ node = new XMLNode(X_("Videoexport"));
+ _session->add_extra_xml(*node);
stop_video_server();
}
editor->queue_visual_videotimeline_update();
}
+void
+ARDOUR_UI::export_video (bool range)
+{
+ if (ARDOUR::Config->get_show_video_export_info()) {
+ ExportVideoInfobox infobox (_session);
+ Gtk::ResponseType rv = (Gtk::ResponseType) infobox.run();
+ if (infobox.show_again()) {
+ ARDOUR::Config->set_show_video_export_info(false);
+ }
+ switch (rv) {
+ case GTK_RESPONSE_YES:
+ PBD::open_uri (ARDOUR::Config->get_reference_manual_url() + "/video-timeline/operations/#export");
+ break;
+ default:
+ break;
+ }
+ }
+ export_video_dialog->set_session (_session);
+ export_video_dialog->apply_state(editor->get_selection().time, range);
+ export_video_dialog->run ();
+ export_video_dialog->hide ();
+}
+
XMLNode*
ARDOUR_UI::mixer_settings () const
{
void
ARDOUR_UI::create_xrun_marker (framepos_t where)
{
- editor->mouse_add_new_marker (where, false, true);
+ if (_session) {
+ Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
+ _session->locations()->add (location);
+ }
}
void
ARDOUR_UI::halt_on_xrun_message ()
{
- MessageDialog msg (*editor,
- _("Recording was stopped because your system could not keep up."));
+ cerr << "HALT on xrun\n";
+ MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up."));
msg.run ();
}
}
const bool cancelled = PluginManager::instance().cancelled();
- if (type != X_("closeme") && !Config->get_show_plugin_scan_window()) {
+ if (type != X_("closeme") && !ui_config->get_show_plugin_scan_window()) {
if (cancelled && scan_dlg->is_mapped()) {
scan_dlg->hide();
gui_idle_handler();
scan_dlg->get_vbox()->pack_start (*scan_tbox, PACK_SHRINK, 4);
}
+ assert(scan_dlg && scan_tbox && cancel_button);
+
if (type == X_("closeme")) {
scan_dlg->hide();
} else {
ARDOUR_UI::reconnect_to_engine ()
{
if (AudioEngine::instance()->start ()) {
+ // TODO somehow make this the topmost window (above any dialogs currently visible)
if (editor) {
MessageDialog msg (*editor, _("Could not reconnect to the Audio/MIDI engine"));
msg.run ();
void
ARDOUR_UI::update_transport_clocks (framepos_t pos)
{
- if (Config->get_primary_clock_delta_edit_cursor()) {
- primary_clock->set (pos, false, editor->get_preferred_edit_position());
+ if (ui_config->get_primary_clock_delta_edit_cursor()) {
+ primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
} else {
primary_clock->set (pos);
}
- if (Config->get_secondary_clock_delta_edit_cursor()) {
- secondary_clock->set (pos, false, editor->get_preferred_edit_position());
+ if (ui_config->get_secondary_clock_delta_edit_cursor()) {
+ secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
} else {
secondary_clock->set (pos);
}
{
CairoWidget::set_flat_buttons( config()->get_flat_buttons() );
}
+
+void
+ARDOUR_UI::audioengine_became_silent ()
+{
+ MessageDialog msg (string_compose (_("This is a free/demo copy of %1. It has just switched to silent mode."), PROGRAM_NAME),
+ true,
+ Gtk::MESSAGE_WARNING,
+ Gtk::BUTTONS_NONE,
+ true);
+
+ msg.set_title (string_compose (_("%1 is now silent"), PROGRAM_NAME));
+
+ Gtk::Label pay_label (string_compose (_("Please consider paying for a copy of %1 - you can pay whatever you want."), PROGRAM_NAME));
+ Gtk::Label subscribe_label (_("Better yet become a subscriber - subscriptions start at US$1 per month."));
+ Gtk::Button pay_button (_("Pay for a copy (via the web)"));
+ Gtk::Button subscribe_button (_("Become a subscriber (via the web)"));
+ Gtk::HBox pay_button_box;
+ Gtk::HBox subscribe_button_box;
+
+ pay_button_box.pack_start (pay_button, true, false);
+ subscribe_button_box.pack_start (subscribe_button, true, false);
+
+ 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 */
+
+ pay_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://ardour.org/download")));
+ subscribe_button.signal_clicked().connect (sigc::hide_return (sigc::bind (sigc::ptr_fun (openuri), (const char*) "https://community.ardour.org/s/subscribe")));
+
+ msg.get_vbox()->pack_start (pay_label);
+ msg.get_vbox()->pack_start (pay_button_box);
+ msg.get_vbox()->pack_start (subscribe_label);
+ msg.get_vbox()->pack_start (subscribe_button_box);
+
+ msg.get_vbox()->show_all ();
+
+ msg.add_button (_("Remain silent"), Gtk::RESPONSE_CANCEL);
+ msg.add_button (_("Save and quit"), Gtk::RESPONSE_NO);
+ msg.add_button (_("Give me more time"), Gtk::RESPONSE_YES);
+
+ int r = msg.run ();
+
+ switch (r) {
+ case Gtk::RESPONSE_YES:
+ AudioEngine::instance()->reset_silence_countdown ();
+ break;
+
+ case Gtk::RESPONSE_NO:
+ /* save and quit */
+ save_state_canfail ("");
+ exit (0);
+ break;
+
+ case Gtk::RESPONSE_CANCEL:
+ default:
+ /* don't reset, save session and exit */
+ break;
+ }
+}
+
+void
+ARDOUR_UI::hide_application ()
+{
+ Application::instance ()-> hide ();
+}