#include <time.h>
#include <cerrno>
#include <fstream>
+#include <stdlib.h>
#include <iostream>
#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 "new_session_dialog.h"
#include "about.h"
#include "splash.h"
+#include "nag.h"
#include "utils.h"
#include "gui_thread.h"
#include "theme_manager.h"
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));
{
ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave));
- if (session->dirty()) {
+ if (session && session->dirty()) {
if (_autosave_connection.connected()) {
_autosave_connection.disconnect();
}
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);
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);
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;
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.
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 ();
Glib::ustring session_path;
Glib::ustring template_name;
int response;
-
+
begin:
response = Gtk::RESPONSE_NONE;
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;
} 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 {
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."));
- pop_back_splash ();
- msg.run ();
- goto out;
- }
-
loading_message (_("Please wait while Ardour loads your session"));
try {
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),
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);
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"
));
}
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 ();
}
}
+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,
image->show();
hbox->show();
+ pop_back_splash ();
+
switch (dialog.run ()) {
case RESPONSE_ACCEPT:
return 1;