diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index 37ffdd9c..8cb8b734 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -237,20 +237,42 @@ Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) { .count()) + " us"); - // As mentioned below, we'll only record the maximum after the first - // report - bridge.logger.log( - "Max processing time: " + - (have_reported - ? std::to_string(std::chrono::duration_cast< - std::chrono::duration>( - max_process_time) - .count()) + - " us" - : "")); + if (process_time_ring_buffer_wrapped_around) { + // We only report these values every few seconds, so we don't need + // to be clever with keeping rolling minima and maxima and we can + // just linearly iterate over everything every now and then + std::chrono::high_resolution_clock::duration min_process_time = + process_time_ring_buffer[0]; + std::chrono::high_resolution_clock::duration max_process_time = + process_time_ring_buffer[0]; + for (size_t i = 1; i < process_time_ring_buffer.size(); i++) { + if (process_time_ring_buffer[i] < min_process_time) { + min_process_time = process_time_ring_buffer[i]; + } else if (process_time_ring_buffer[i] > max_process_time) { + max_process_time = process_time_ring_buffer[i]; + } + } + + bridge.logger.log( + "Min processing time: " + + std::to_string(std::chrono::duration_cast< + std::chrono::duration>( + min_process_time) + .count()) + + " us"); + bridge.logger.log( + "Max processing time: " + + std::to_string(std::chrono::duration_cast< + std::chrono::duration>( + max_process_time) + .count()) + + " us"); + } else { + bridge.logger.log("Min processing time: "); + bridge.logger.log("Max processing time: "); + } last_report = now; - have_reported = true; } // Doing this twice is a bit of a waste, but we don't want to measure IO @@ -306,11 +328,13 @@ Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) { std::chrono::high_resolution_clock::duration>( (process_time * 0.05) + (mean_process_time * 0.95)); - // With the current implementation we may need to resize our buffers in the - // first call, so we'll give ourselves a bit of a grace period to allow the - // buffers to warm up - if (have_reported) { - max_process_time = std::max(process_time, max_process_time); + // For the minma and maxima we keep the last `process_time_ring_buffer_size` + // timings around so we can compute these during the report + process_time_ring_buffer[process_time_ring_buffer_pos] = process_time; + process_time_ring_buffer_pos += 1; + if (process_time_ring_buffer_pos >= process_time_ring_buffer.size()) { + process_time_ring_buffer_pos = 0; + process_time_ring_buffer_wrapped_around = true; } return process_response.result; diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.h b/src/plugin/bridges/vst3-impls/plugin-proxy.h index 747de6b4..c1eb878c 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.h +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.h @@ -19,6 +19,8 @@ #include "../vst3.h" #include "plug-view-proxy.h" +constexpr size_t process_time_ring_buffer_size = 2048; + /** * Here we pass though all function calls made by the host to the Windows VST3 * plugin. We had to deviate from yabridge's 'one-to-one passthrough' philosphy @@ -555,19 +557,21 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { */ std::chrono::high_resolution_clock::duration mean_process_time = std::chrono::high_resolution_clock::duration::zero(); + /** - * The maximum time it took to handle `YaAudioProcessor::process()`. + * A ring buffer for calculating the rolling minimum and maximum for the + * time it takes to handle `YaAudioProcessor::process()`. Since we only + * report the maximum every five seconds, we don't need to be clever with + * rolling maxima and can just iterate over it every five seconds. */ - std::chrono::high_resolution_clock::duration max_process_time = - std::chrono::high_resolution_clock::duration::zero(); + std::array + process_time_ring_buffer; + size_t process_time_ring_buffer_pos = 0; + bool process_time_ring_buffer_wrapped_around = false; /** * The last time we reported the mean processing time. */ std::chrono::high_resolution_clock::time_point last_report; - /** - * We'll wait with reporting the maximum processing time until the first - * report to allow buffers to warm up. - */ - bool have_reported = false; };