#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
+#include <time.h>
#include <cerrno>
#include <fstream>
+#include <stdlib.h>
#include <iostream>
#include <pbd/error.h>
#include <pbd/basename.h>
#include <pbd/compose.h>
-#include <pbd/misc.h>
#include <pbd/pathscanner.h>
#include <pbd/failed_constructor.h>
#include <pbd/enumwriter.h>
#include <ardour/audioengine.h>
#include <ardour/playlist.h>
#include <ardour/utils.h>
+#include <ardour/plugin.h>
#include <ardour/audio_diskstream.h>
#include <ardour/audiofilesource.h>
#include <ardour/recent_sessions.h>
#include <ardour/port.h>
#include <ardour/audio_track.h>
+typedef uint64_t microseconds_t;
+
#include "actions.h"
#include "ardour_ui.h"
#include "public_editor.h"
#include "new_session_dialog.h"
#include "about.h"
#include "splash.h"
+#include "nag.h"
#include "utils.h"
#include "gui_thread.h"
#include "theme_manager.h"
#include "engine_dialog.h"
+#include "gain_meter.h"
+#include "route_time_axis.h"
#include "i18n.h"
preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true),
postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true),
- /* adjuster table */
-
- adjuster_table (3, 3),
-
/* preroll stuff */
preroll_button (_("pre\nroll")),
shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl),
shuttle_controller_binding_proxy (shuttle_controllable),
- roll_button (roll_controllable),
- stop_button (stop_controllable),
- goto_start_button (goto_start_controllable),
- goto_end_button (goto_end_controllable),
- auto_loop_button (auto_loop_controllable),
- play_selection_button (play_selection_controllable),
- rec_button (rec_controllable),
+ roll_button (&roll_controllable),
+ stop_button (&stop_controllable),
+ goto_start_button (&goto_start_controllable),
+ goto_end_button (&goto_end_controllable),
+ auto_loop_button (&auto_loop_controllable),
+ play_selection_button (&play_selection_controllable),
+ rec_button (&rec_controllable),
shuttle_units_button (_("% ")),
_auto_display_errors = false;
#endif
- if (getenv ("ARDOUR_DEBUG_UPDATES")) {
- gdk_window_set_debug_updates (true);
- }
-
about = 0;
splash = 0;
_will_create_new_session_automatically = false;
session_loaded = false;
last_speed_displayed = -1.0f;
+ ignore_dual_punch = false;
+ _mixer_on_top = false;
- keybindings_path = ARDOUR::find_config_file ("ardour.bindings");
- /* all changes go to the user directory */
- user_keybindings_path = get_user_ardour_path ();
- user_keybindings_path += '/';
- user_keybindings_path += "ardour.bindings";
+ roll_button.unset_flags (Gtk::CAN_FOCUS);
+ stop_button.unset_flags (Gtk::CAN_FOCUS);
+ goto_start_button.unset_flags (Gtk::CAN_FOCUS);
+ goto_end_button.unset_flags (Gtk::CAN_FOCUS);
+ auto_loop_button.unset_flags (Gtk::CAN_FOCUS);
+ play_selection_button.unset_flags (Gtk::CAN_FOCUS);
+ rec_button.unset_flags (Gtk::CAN_FOCUS);
- can_save_keybindings = false;
-
- last_configure_time.tv_sec = 0;
- last_configure_time.tv_usec = 0;
+ last_configure_time= 0;
shuttle_grabbed = false;
shuttle_fract = 0.0;
shuttle_style_menu = 0;
shuttle_unit_menu = 0;
- gettimeofday (&last_peak_grab, 0);
- gettimeofday (&last_shuttle_request, 0);
+ // We do not have jack linked in yet so;
+
+ last_shuttle_request = last_peak_grab = 0; // get_microseconds();
ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
+ ARDOUR::Plugin::PresetFileExists.connect (mem_fun(*this, &ARDOUR_UI::preset_file_exists_handler));
+
+ /* handle dialog requests */
+
+ ARDOUR::Session::Dialog.connect (mem_fun(*this, &ARDOUR_UI::session_dialog));
+
/* handle pending state with a dialog */
ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
Config->set_current_owner (ConfigVariableBase::Interface);
setup_profile ();
+ GainMeter::setup_slider_pix ();
+ RouteTimeAxisView::setup_slider_pix ();
+
} catch (failed_constructor& err) {
error << _("could not initialize Ardour.") << endmsg;
// pass it on up
keyboard = new Keyboard;
+ reset_dpi();
+
starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
/* set default clock modes */
- primary_clock.set_mode (AudioClock::SMPTE);
- secondary_clock.set_mode (AudioClock::BBT);
+ if (Profile->get_sae()) {
+ primary_clock.set_mode (AudioClock::BBT);
+ secondary_clock.set_mode (AudioClock::MinSec);
+ } else {
+ primary_clock.set_mode (AudioClock::SMPTE);
+ secondary_clock.set_mode (AudioClock::BBT);
+ }
/* start the time-of-day-clock */
}
}
+void
+ARDOUR_UI::pop_back_splash ()
+{
+ if (Splash::instance()) {
+ // Splash::instance()->pop_back();
+ Splash::instance()->hide ();
+ }
+}
+
gint
ARDOUR_UI::configure_timeout ()
{
- struct timeval now;
- struct timeval diff;
-
- if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
+ if (last_configure_time == 0) {
/* no configure events yet */
return TRUE;
}
- gettimeofday (&now, 0);
- timersub (&now, &last_configure_time, &diff);
-
/* force a gap of 0.5 seconds since the last configure event
*/
- if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
+ if (get_microseconds() - last_configure_time < 500000) {
return TRUE;
} else {
have_configure_timeout = false;
ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
{
if (have_configure_timeout) {
- gettimeofday (&last_configure_time, 0);
+ last_configure_time = get_microseconds();
} else {
Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
have_configure_timeout = true;
Config->add_instant_xml (mnode, get_user_ardour_path());
}
- save_keybindings ();
+ Keyboard::save_keybindings ();
}
gint
ARDOUR_UI::autosave_session ()
{
+ if (g_main_depth() > 1) {
+ /* inside a recursive main loop,
+ give up because we may not be able to
+ take a lock.
+ */
+ return 1;
+ }
+
if (!Config->get_periodic_safety_backups())
return 1;
{
ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
- if (session->dirty()) {
+ if (session && session->dirty()) {
if (_autosave_connection.connected()) {
_autosave_connection.disconnect();
}
win.show_all ();
win.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash ();
/* we just don't care about the result, but we want to block */
ARDOUR_UI::startup ()
{
string name, path;
-
+
new_session_dialog = new NewSessionDialog();
bool backend_audio_is_running = EngineControl::engine_running();
return;
}
+ BootMessage (_("Ardour is ready for use"));
show ();
}
hbox.pack_start (cb, true, false);
vbox->pack_start (hbox);
hbox.show_all ();
+
+ pop_back_splash ();
msg.run ();
}
Ardour was unable to save your session.\n\n\
If you still wish to quit, please use the\n\n\
\"Just quit\" option."));
+ pop_back_splash();
msg.run ();
return;
}
session->set_deletion_in_progress ();
}
+ ArdourDialog::close_all_dialogs ();
engine->stop (true);
save_ardour_state ();
quit ();
window.set_resizable (false);
window.show_all ();
- save_the_session = 0;
-
window.set_keep_above (true);
window.present ();
ARDOUR_UI::update_buffer_load ()
{
char buf[64];
+ uint32_t c, p;
if (session) {
+ c = session->capture_load ();
+ p = session->playback_load ();
+
+ push_buffer_stats (c, p);
+
snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
session->playback_load(), session->capture_load());
buffer_load_label.set_text (buf);
}
}
-bool
-ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info)
-{
- struct stat statbuf;
-
- if (stat (info.filename.c_str(), &statbuf) != 0) {
- return false;
- }
-
- if (!S_ISDIR(statbuf.st_mode)) {
- return false;
- }
-
- // XXX Portability
-
- string session_file = info.filename;
- session_file += '/';
- session_file += Glib::path_get_basename (info.filename);
- session_file += ".ardour";
-
- if (stat (session_file.c_str(), &statbuf) != 0) {
- return false;
- }
-
- return S_ISREG (statbuf.st_mode);
-}
-
bool
ARDOUR_UI::check_audioengine ()
{
if (!engine->connected()) {
MessageDialog msg (_("Ardour is not connected to JACK\n"
"You cannot open or close sessions in this condition"));
+ pop_back_splash ();
+ msg.set_position (WIN_POS_CENTER);
msg.run ();
return false;
}
/* ardour sessions are folders */
- open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
+ open_session_selector = new Gtk::FileChooserDialog (_("Open Session"), FILE_CHOOSER_ACTION_OPEN);
open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
open_session_selector->set_default_response(Gtk::RESPONSE_ACCEPT);
to create a new track or bus.\n\
You should save Ardour, exit and\n\
restart JACK with more ports."));
+ pop_back_splash ();
msg.run ();
}
}
}
void
-ARDOUR_UI::transport_goto_start ()
+ARDOUR_UI::transport_goto_start ()
{
if (session) {
session->goto_start();
}
}
+void
+ARDOUR_UI::transport_goto_wallclock ()
+{
+ if (session && editor) {
+
+ time_t now;
+ struct tm tmnow;
+ nframes64_t frames;
+
+ time (&now);
+ localtime_r (&now, &tmnow);
+
+ frames = tmnow.tm_hour * (60 * 60 * session->frame_rate());
+ frames += tmnow.tm_min * (60 * session->frame_rate());
+ frames += tmnow.tm_sec * session->frame_rate();
+
+ session->request_locate (frames);
+
+ /* force displayed area in editor to start no matter
+ what "follow playhead" setting is.
+ */
+
+ if (editor) {
+ editor->reset_x_origin (frames - (editor->current_page_frames()/2));
+ }
+ }
+}
+
void
ARDOUR_UI::transport_goto_end ()
{
void
ARDOUR_UI::transport_record (bool roll)
{
+
if (session) {
switch (session->record_status()) {
case Session::Disabled:
session->disable_record (false, true);
}
}
+ //cerr << "ARDOUR_UI::transport_record () called roll = " << roll << " session->record_status() = " << session->record_status() << endl;
}
void
rolling = session->transport_rolling ();
+ //cerr << "ARDOUR_UI::transport_roll () called session->record_status() = " << session->record_status() << endl;
+
if (session->get_play_loop()) {
session->request_play_loop (false);
auto_loop_button.set_visual_state (1);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
Glib::RefPtr<Action> action;
- char* action_name = 0;
+ const char* action_name = 0;
switch (engine->frames_per_cycle()) {
case 32:
_("\
JACK has either been shutdown or it\n\
disconnected Ardour because Ardour\n\
-was not fast enough. You can save the\n\
-session and/or try to reconnect to JACK ."));
+was not fast enough. Try to restart\n\
+JACK, reconnect and save the session."));
+ pop_back_splash ();
msg.run ();
}
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"));
prompter.set_initial_text (timebuf);
-
+
+ again:
switch (prompter.run()) {
case RESPONSE_ACCEPT:
prompter.get_result (snapname);
if (snapname.length()){
+ if (snapname.find ('/') != string::npos) {
+ MessageDialog msg (_("To ensure compatibility with various systems\n"
+ "snapshot names may not contain a '/' character"));
+ msg.run ();
+ goto again;
+ }
+ if (snapname.find ('\\') != string::npos) {
+ MessageDialog msg (_("To ensure compatibility with various systems\n"
+ "snapshot names may not contain a '\\' character"));
+ msg.run ();
+ goto again;
+ }
save_state (snapname);
}
break;
return 0;
}
-void
-ARDOUR_UI::restore_state (string name)
-{
- if (session) {
- if (name.length() == 0) {
- name = session->name();
- }
- session->restore_state (name);
- }
-}
-
void
ARDOUR_UI::primary_clock_value_changed ()
{
}
}
-void
-ARDOUR_UI::rec_enable_button_blink (bool onoff, AudioDiskstream *dstream, Widget *w)
-{
- if (session && dstream && dstream->record_enabled()) {
-
- Session::RecordState rs;
-
- rs = session->record_status ();
-
- switch (rs) {
- case Session::Disabled:
- case Session::Enabled:
- if (w->get_state() != STATE_SELECTED) {
- w->set_state (STATE_SELECTED);
- }
- break;
-
- case Session::Recording:
- if (w->get_state() != STATE_ACTIVE) {
- w->set_state (STATE_ACTIVE);
- }
- break;
- }
-
- } else {
- if (w->get_state() != STATE_NORMAL) {
- w->set_state (STATE_NORMAL);
- }
- }
-}
-
void
ARDOUR_UI::transport_rec_enable_blink (bool onoff)
{
}
}
-gint
-ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
-{
- window->hide();
- Gtk::Main::quit ();
- return TRUE;
-}
-
void
ARDOUR_UI::save_template ()
-
{
ArdourPrompter prompter (true);
string name;
}
prompter.set_name (X_("Prompter"));
+ prompter.set_title (_("Save Mix Template"));
prompter.set_prompt (_("Name for mix template:"));
prompter.set_initial_text(session->name() + _("-template"));
prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
void
ARDOUR_UI::fontconfig_dialog ()
{
+#if 0
+ /* this issue seems to have gone away with changes to font handling in GTK/Quartz
+ */
#ifdef GTKOSX
/* X11 users will always have fontconfig info around, but new GTK-OSX users
may not and it can take a while to build it. Warn them.
true,
Gtk::MESSAGE_INFO,
Gtk::BUTTONS_OK);
+ pop_back_splash ();
msg.show_all ();
msg.present ();
msg.run ();
}
#endif
+#endif
}
void
msg.set_name (X_("CleanupDialog"));
+ msg.set_title (_("Cleanup Unused Sources"));
msg.set_wmclass (X_("existing_session"), "Ardour");
msg.set_position (Gtk::WIN_POS_MOUSE);
-
+ pop_back_splash ();
+
switch (msg.run()) {
case RESPONSE_YES:
return true;
void
ARDOUR_UI::loading_message (const std::string& msg)
{
- cerr << "say: " << msg << endl;
show_splash ();
splash->message (msg);
flush_pending ();
}
-
+
+void
+ARDOUR_UI::idle_load (const Glib::ustring& 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));
+ }
+ } else {
+
+ ARDOUR_COMMAND_LINE::session_name = path;
+
+ if (new_session_dialog) {
+
+
+ /* make it break out of Dialog::run() and
+ start again.
+ */
+
+ new_session_dialog->response (1);
+ }
+ }
+}
+
bool
ARDOUR_UI::get_session_parameters (bool backend_audio_is_running, bool should_be_new)
{
Glib::ustring session_name;
Glib::ustring session_path;
Glib::ustring template_name;
-
- int response = Gtk::RESPONSE_NONE;
+ int response;
+
+ begin:
+ response = Gtk::RESPONSE_NONE;
if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
/* handle possible negative responses */
switch (response) {
+ case 1:
+ /* sent by idle_load, meaning restart the whole process again */
+ new_session_dialog->hide();
+ new_session_dialog->reset();
+ goto begin;
+ break;
+
case Gtk::RESPONSE_CANCEL:
case Gtk::RESPONSE_DELETE_EVENT:
if (!session) {
+ if (engine && engine->running()) {
+ engine->stop (true);
+ }
quit();
}
new_session_dialog->hide ();
fontconfig_dialog();
if (!backend_audio_is_running) {
- if (new_session_dialog->engine_control.setup_engine ()) {
- new_session_dialog->hide ();
+ int ret = new_session_dialog->engine_control.setup_engine ();
+ if (ret < 0) {
return false;
- }
+ } else if (ret > 0) {
+ response = Gtk::RESPONSE_REJECT;
+ goto try_again;
+ }
+
+ /* hide the NSD while we start up the engine */
+
+ new_session_dialog->hide ();
+ flush_pending ();
}
-
+
if (create_engine ()) {
backend_audio_error (!backend_audio_is_running, new_session_dialog);
flush_pending ();
new_session_dialog->set_existing_session (false);
- new_session_dialog->set_current_page (2);
+ new_session_dialog->set_current_page (0); // new engine page
+ new_session_dialog->engine_control.unset_interface_chosen ();
response = Gtk::RESPONSE_NONE;
goto try_again;
if (session_name[0] == '/' ||
(session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') ||
(session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) {
-
+
session_path = Glib::path_get_dirname (session_name);
session_name = Glib::path_get_basename (session_name);
} else {
session_path = new_session_dialog->session_folder();
+
}
template_name = Glib::ustring();
switch (new_session_dialog->which_page()) {
case NewSessionDialog::OpenPage:
- case NewSessionDialog::EnginePage:
goto loadit;
break;
+ case NewSessionDialog::EnginePage:
+ if (new_session_dialog->engine_control.interface_chosen() && !session_path.empty()) {
+ goto loadit;
+ } else {
+ goto try_again;
+ }
+ break;
+
case NewSessionDialog::NewPage: /* nominally the "new" session creator, but could be in use for an old session */
should_be_new = true;
-
+
+ if (session_name.find ('/') != Glib::ustring::npos) {
+ MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
+ "session names may not contain a '/' character"));
+ msg.run ();
+ response = RESPONSE_NONE;
+ goto try_again;
+ }
+
+ if (session_name.find ('\\') != Glib::ustring::npos) {
+ MessageDialog msg (*new_session_dialog, _("To ensure compatibility with various systems\n"
+ "session names may not contain a '\\' character"));
+ msg.run ();
+ response = RESPONSE_NONE;
+ goto try_again;
+ }
+
//XXX This is needed because session constructor wants a
//non-existant path. hopefully this will be fixed at some point.
-
+
session_path = Glib::build_filename (session_path, session_name);
if (Glib::file_test (session_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) {
+ new_session_dialog->hide ();
+
if (ask_about_loading_existing_session (session_path)) {
goto loadit;
} else {
loadit:
new_session_dialog->hide ();
-
+
if (load_session (session_path, session_name, template_name)) {
/* force a retry */
response = Gtk::RESPONSE_NONE;
}
}
- } while (response == Gtk::RESPONSE_NONE);
+ } while (response == Gtk::RESPONSE_NONE || response == Gtk::RESPONSE_REJECT);
done:
show();
return;
}
- unload_session (true);
+ if (unload_session (true)) {
+ return;
+ }
get_session_parameters (true, false);
}
goto out;
}
- /* if it already exists, we must have write access */
-
- if (Glib::file_test (path.c_str(), Glib::FILE_TEST_EXISTS) && ::access (path.c_str(), W_OK)) {
- MessageDialog msg (*editor, _("You do not have write access to this session.\n"
- "This prevents the session from being loaded."));
- msg.run ();
- goto out;
- }
-
loading_message (_("Please wait while Ardour loads your session"));
- disable_screen_updates ();
try {
new_session = new Session (*engine, path, snap_name, mix_template);
MessageDialog msg (err.what(),
true,
Gtk::MESSAGE_INFO,
- Gtk::BUTTONS_OK_CANCEL);
+ Gtk::BUTTONS_CLOSE);
- msg.set_title (_("Loading Error"));
- msg.set_secondary_text (_("Click the OK button to try again."));
+ msg.set_title (_("Port Registration Error"));
+ msg.set_secondary_text (_("Click the Close button to try again."));
msg.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash ();
msg.present ();
int response = msg.run ();
goto out;
}
+ /* this exception is also special */
+
+ catch (Session::SRMismatchRejected& err) {
+ goto out; /* just go back and reload something else, etc. */
+ }
+
catch (...) {
MessageDialog msg (string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name),
true,
Gtk::MESSAGE_INFO,
- Gtk::BUTTONS_OK_CANCEL);
+ Gtk::BUTTONS_CLOSE);
msg.set_title (_("Loading Error"));
- msg.set_secondary_text (_("Click the OK button to try again."));
+ msg.set_secondary_text (_("Click the Close button to try again."));
msg.set_position (Gtk::WIN_POS_CENTER);
+ pop_back_splash ();
msg.present ();
int response = msg.run ();
session->set_clean ();
}
- enable_screen_updates ();
flush_pending ();
retval = 0;
catch (...) {
MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path));
+ pop_back_splash ();
msg.run ();
return -1;
}
connect_to_session (new_session);
session_loaded = true;
+
+ new_session->save_state(new_session->name());
+
return 0;
}
about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) );
}
+ about->set_transient_for(*editor);
+
about->show_all ();
}
+void
+ARDOUR_UI::launch_chat ()
+{
+#ifdef __APPLE__
+ NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour-osx");
+#else
+ NagScreen::open_uri("http://webchat.freenode.net/?channels=ardour");
+#endif
+}
+
void
ARDOUR_UI::hide_about ()
{
}
void
-ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
+ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title,
+ const string& plural_msg, const string& singular_msg)
{
size_t removed;
dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP);
- if (rep.space < 1048576.0f) {
- if (removed > 1) {
- txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
- } else {
- txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo"));
- }
+
+ /* subst:
+ %1 - number of files removed
+ %2 - location of "dead_sounds"
+ %3 - size of files affected
+ %4 - prefix for "bytes" to produce sensible results (e.g. mega, kilo, giga)
+ */
+
+ const char* bprefix;
+ float space_adjusted;
+
+ if (rep.space < 1000000.0f) {
+ bprefix = X_("kilo");
+ space_adjusted = truncf((float)rep.space / 1000.0f);
+ } else if (rep.space < (1000000.0f * 1000)) {
+ bprefix = X_("mega");
+ space_adjusted = truncf((float)rep.space / (1000000.0f));
} else {
- if (removed > 1) {
- txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
- } else {
- txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega"));
- }
+ bprefix = X_("giga");
+ space_adjusted = truncf((float)rep.space / (1000000.0f * 1000));
+ }
+
+ if (removed > 1) {
+ txt.set_text (string_compose (plural_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
+ } else {
+ txt.set_text (string_compose (singular_msg, removed, session->path() + "dead_sounds", space_adjusted, bprefix));
}
dhbox.pack_start (*dimage, true, false, 5);
}
if (session->cleanup_sources (rep)) {
+ editor->finish_cleanup ();
return;
}
+
+ editor->finish_cleanup ();
checker.hide();
display_cleanup_results (rep,
_("cleaned files"),
_("\
-The following %1 %2 not in use and \n\
+The following %1 files were not in use and \n\
have been moved to:\n\
-%3. \n\n\
+%2. \n\n\
Flushing the wastebasket will \n\
release an additional\n\
-%4 %5bytes of disk space.\n"
+%3 %4bytes of disk space.\n"),
+ _("\
+The following file was not in use and \n \
+has been moved to:\n \
+%2. \n\n\
+Flushing the wastebasket will \n\
+release an additional\n\
+%3 %4bytes of disk space.\n"
));
-
-
}
void
display_cleanup_results (rep,
_("deleted file"),
- _("The following %1 %2 deleted from\n\
-%3,\n\
-releasing %4 %5bytes of disk space"));
+ _("The following %1 files were deleted from\n\
+%2,\n\
+releasing %3 %4bytes of disk space"),
+ _("The following file was deleted from\n\
+%2,\n\
+releasing %3 %4bytes of disk space"));
}
void
return;
}
+ string template_path = add_route_dialog->track_template();
+
+ if (!template_path.empty()) {
+ session->new_route_from_template (count, template_path);
+ return;
+ }
+
uint32_t input_chan = add_route_dialog->channels ();
uint32_t output_chan;
string name_template = add_route_dialog->name_template ();
} else {
node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
}
+
+ if (!node) {
+ if (getenv("ARDOUR_INSTANT_XML_PATH")) {
+ node = Config->instant_xml(X_("Editor"), getenv("ARDOUR_INSTANT_XML_PATH"));
+ }
+ }
if (!node) {
node = new XMLNode (X_("Editor"));
}
void
-ARDOUR_UI::halt_on_xrun_message ()
+ARDOUR_UI::create_xrun_marker(nframes_t where)
{
- ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message));
+ editor->mouse_add_new_marker (where, false, true);
+}
+void
+ARDOUR_UI::halt_on_xrun_message ()
+{
MessageDialog msg (*editor,
_("Recording was stopped because your system could not keep up."));
msg.run ();
}
+void
+ARDOUR_UI::xrun_handler(nframes_t where)
+{
+ if (!session) {
+ return;
+ }
+
+ ENSURE_GUI_THREAD (bind(mem_fun(*this, &ARDOUR_UI::xrun_handler), where));
+
+ if (session && Config->get_create_xrun_marker() && session->actively_recording()) {
+ create_xrun_marker(where);
+ }
+
+ if (session && Config->get_stop_recording_on_xrun() && session->actively_recording()) {
+ halt_on_xrun_message ();
+ }
+}
+
+bool
+ARDOUR_UI::preset_file_exists_handler ()
+{
+ /* if driven from another thread, say "do not overwrite" and show the user nothing.
+ */
+
+ if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) { \
+ return false;
+ }
+
+ HBox* hbox = new HBox();
+ Image* image = new Image (Stock::DIALOG_QUESTION, ICON_SIZE_DIALOG);
+ Gtk::Dialog dialog (_("Preset Exists"), true, false);
+ Label message (_("\
+A preset with this name already exists for this plugin.\n\
+\n\
+What you would like to do?\n"));
+ image->set_alignment(ALIGN_CENTER, ALIGN_TOP);
+ hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
+ hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
+ dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
+ dialog.add_button (_("Overwrite the existing preset"), RESPONSE_ACCEPT);
+ dialog.add_button (_("Leave the existing preset alone"), RESPONSE_REJECT);
+ dialog.set_default_response (RESPONSE_ACCEPT);
+ dialog.set_position (WIN_POS_MOUSE);
+ dialog.set_type_hint (Gdk::WINDOW_TYPE_HINT_UTILITY); // need to make it float above the preset name dialog
+
+ message.show();
+ image->show();
+ hbox->show();
+
+ switch (dialog.run ()) {
+ case RESPONSE_ACCEPT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void
+ARDOUR_UI::push_buffer_stats (uint32_t capture, uint32_t playback)
+{
+ time_t now;
+ time (&now);
+
+ while (disk_buffer_stats.size() > 60) {
+ disk_buffer_stats.pop_front ();
+ }
+
+ disk_buffer_stats.push_back (DiskBufferStat (now, capture, playback));
+}
+
+void
+ARDOUR_UI::write_buffer_stats ()
+{
+ std::ofstream fout;
+ struct tm tm;
+ char buf[64];
+ char path[PATH_MAX+1]; int fd;
+
+ strcpy (path, "ardourBufferingXXXXXX");
+
+ if ((fd = mkstemp (path )) < 0) {
+ cerr << X_("cannot find temporary name for ardour buffer stats") << endl;
+ return;
+ }
+
+ fout.open (path);
+ close (fd);
+
+ if (!fout) {
+ cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), path) << endl;
+ return;
+ }
+
+ for (list<DiskBufferStat>::iterator i = disk_buffer_stats.begin(); i != disk_buffer_stats.end(); ++i) {
+ localtime_r (&(*i).when, &tm);
+ strftime (buf, sizeof (buf), "%T", &tm);
+ fout << buf << ' ' << (*i).capture << ' ' << (*i).playback << endl;
+ }
+
+ disk_buffer_stats.clear ();
+
+ fout.close ();
+
+ cerr << "Ardour buffering statistics can be found in: " << path << endl;
+ free (path);
+}
+
void
ARDOUR_UI::disk_overrun_handler ()
{
+
ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
+ write_buffer_stats ();
+
if (!have_disk_speed_dialog_displayed) {
have_disk_speed_dialog_displayed = true;
MessageDialog* msg = new MessageDialog (*editor, _("\
void
ARDOUR_UI::disk_underrun_handler ()
{
+
ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
+ write_buffer_stats ();
+
if (!have_disk_speed_dialog_displayed) {
have_disk_speed_dialog_displayed = true;
MessageDialog* msg = new MessageDialog (*editor,
delete msg;
}
+void
+ARDOUR_UI::session_dialog (std::string msg)
+{
+ ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::session_dialog), msg));
+
+ MessageDialog* d;
+
+ if (editor) {
+ d = new MessageDialog (*editor, msg, false, MESSAGE_INFO, BUTTONS_OK, true);
+ } else {
+ d = new MessageDialog (msg, false, MESSAGE_INFO, BUTTONS_OK, true);
+ }
+
+ d->show_all ();
+ d->run ();
+ delete d;
+}
+
int
ARDOUR_UI::pending_state_dialog ()
{
image->show();
hbox->show();
+ pop_back_splash ();
+
switch (dialog.run ()) {
case RESPONSE_ACCEPT:
return 1;
hbox->pack_start (*image, PACK_EXPAND_WIDGET, 12);
hbox->pack_end (message, PACK_EXPAND_PADDING, 12);
dialog.get_vbox()->pack_start(*hbox, PACK_EXPAND_PADDING, 6);
- dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
dialog.add_button (_("Do not load session"), RESPONSE_REJECT);
+ dialog.add_button (_("Load session anyway"), RESPONSE_ACCEPT);
dialog.set_default_response (RESPONSE_ACCEPT);
dialog.set_position (WIN_POS_CENTER);
message.show();
}
}
-void
-ARDOUR_UI::set_keybindings_path (string path)
-{
- keybindings_path = path;
-}
-
-void
-ARDOUR_UI::save_keybindings ()
-{
- if (can_save_keybindings) {
- AccelMap::save (user_keybindings_path);
- }
-}
-
bool
ARDOUR_UI::first_idle ()
{
if (session) {
session->allow_auto_play (true);
}
- can_save_keybindings = true;
+
+ if (editor) {
+ editor->first_idle();
+ }
+
+ Keyboard::set_can_save_keybindings (true);
return false;
}
return;
}
- char *action = 0;
+ const char *action = 0;
switch (type) {
case Roll: