diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index ce435c4ad5..861feef6aa 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -909,8 +909,14 @@ void 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); @@ -2932,11 +2938,61 @@ ARDOUR_UI::xrun_handler(nframes_t where) } } +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; + + if ((path = tempnam (0, "ardourBuffering")) == 0) { + cerr << X_("cannot find temporary name for ardour buffer stats") << endl; + return; + } + + fout.open (path); + + if (!fout) { + cerr << string_compose (X_("cannot open file %1 for ardour buffer stats"), path) << endl; + return; + } + + for (list::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, _("\ @@ -2953,8 +3009,11 @@ quickly enough to keep up with recording.\n")); 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, diff --git a/gtk2_ardour/ardour_ui.h b/gtk2_ardour/ardour_ui.h index 81a8de0af4..f87e007ddd 100644 --- a/gtk2_ardour/ardour_ui.h +++ b/gtk2_ardour/ardour_ui.h @@ -20,6 +20,8 @@ #ifndef __ardour_gui_h__ #define __ardour_gui_h__ +#include + /* need _BSD_SOURCE to get timersub macros */ #ifdef _BSD_SOURCE @@ -31,7 +33,6 @@ #endif #include - #include #include @@ -637,6 +638,19 @@ class ARDOUR_UI : public Gtkmm2ext::UI ARDOUR::microseconds_t last_peak_grab; ARDOUR::microseconds_t last_shuttle_request; + struct DiskBufferStat { + time_t when; + uint32_t capture; + uint32_t playback; + + DiskBufferStat (time_t w, uint32_t c, uint32_t p) + : when (w), capture (c), playback (p) {} + }; + + std::list disk_buffer_stats; + void push_buffer_stats (uint32_t, uint32_t); + void write_buffer_stats (); + bool have_disk_speed_dialog_displayed; void disk_speed_dialog_gone (int ignored_response, Gtk::MessageDialog*); void disk_overrun_handler ();