From a65b1ddedc28a4135057dd48782f4cfa5d1411ea Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Thu, 27 Aug 2015 17:09:04 +1000 Subject: [PATCH] Add a DSPLoadCalculator class to the PortAudioBackend for DSP load calculation The class uses the same algorithm as in the coreaudio and alsa backends and should probably go into libardour at some point --- libs/backends/portaudio/dsp_load_calculator.h | 88 +++++++++++++++++++ libs/backends/portaudio/portaudio_backend.cc | 22 ++--- libs/backends/portaudio/portaudio_backend.h | 3 + 3 files changed, 102 insertions(+), 11 deletions(-) create mode 100644 libs/backends/portaudio/dsp_load_calculator.h diff --git a/libs/backends/portaudio/dsp_load_calculator.h b/libs/backends/portaudio/dsp_load_calculator.h new file mode 100644 index 0000000000..2ae9209746 --- /dev/null +++ b/libs/backends/portaudio/dsp_load_calculator.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 Tim Mayberry + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef DSP_LOAD_CALCULATOR_H +#define DSP_LOAD_CALCULATOR_H + +#include + +class DSPLoadCalculator { +public: + DSPLoadCalculator() + : m_max_time_us(0) + , m_start_timestamp_us(0) + , m_stop_timestamp_us(0) + , m_dsp_load(0.0f) + { + } + + void set_max_time_us(uint64_t max_time_us) { m_max_time_us = max_time_us; } + + uint64_t get_max_time_us() { return m_max_time_us; } + + void set_start_timestamp_us(uint64_t start_timestamp_us) + { + m_start_timestamp_us = start_timestamp_us; + } + + void set_stop_timestamp_us(uint64_t stop_timestamp_us) + { + m_stop_timestamp_us = stop_timestamp_us; + + if (elapsed_time_us() > m_max_time_us) { + m_dsp_load = 1.0f; + } else { + const float load = elapsed_time_us() / (float)m_max_time_us; + if (load > m_dsp_load) { + m_dsp_load = load; + } else { + const float alpha = 0.2f * (m_max_time_us * 1e-6f); + m_dsp_load = m_dsp_load + alpha * (load - m_dsp_load) + 1e-12; + } + } + } + + uint64_t elapsed_time_us() + { + return m_stop_timestamp_us - m_start_timestamp_us; + } + + /** + * @return a decimal value between 0.0 and 1.0 representing the percentage + * of time spent between start and stop in proportion to the max expected time + * in microseconds(us). + */ + float get_dsp_load() + { + if (m_dsp_load > m_max_time_us) { + return 1.0f; + } + if (m_dsp_load < 0.0f) { + return 0.0f; + } + return m_dsp_load; + } + +private: + uint64_t m_max_time_us; + uint64_t m_start_timestamp_us; + uint64_t m_stop_timestamp_us; + float m_dsp_load; +}; + +#endif // DSP_LOAD_CALCULATOR_H diff --git a/libs/backends/portaudio/portaudio_backend.cc b/libs/backends/portaudio/portaudio_backend.cc index 698f21881f..142614bbff 100644 --- a/libs/backends/portaudio/portaudio_backend.cc +++ b/libs/backends/portaudio/portaudio_backend.cc @@ -516,6 +516,8 @@ PortAudioBackend::_start (bool for_latency_measurement) m_cycle_timer.set_samplerate(_samplerate); m_cycle_timer.set_samples_per_cycle(_samples_per_period); + m_dsp_calc.set_max_time_us (m_cycle_timer.get_length_us()); + DEBUG_MIDI ("Registering MIDI ports\n"); if (register_system_midi_ports () != 0) { @@ -1477,13 +1479,10 @@ bool PortAudioBackend::blocking_process_main () { uint32_t i = 0; - uint64_t clock1, clock2; - int64_t min_elapsed_us = 1000000; - int64_t max_elapsed_us = 0; - const int64_t nomial_time = 1e6 * _samples_per_period / _samplerate; - // const int64_t nomial_time = m_cycle_timer.get_length_us(); + uint64_t min_elapsed_us = 1000000; + uint64_t max_elapsed_us = 0; - clock1 = utils::get_microseconds(); + m_dsp_calc.set_start_timestamp_us (utils::get_microseconds()); /* get audio */ i = 0; @@ -1605,12 +1604,13 @@ PortAudioBackend::blocking_process_main () _processed_samples += _samples_per_period; /* calculate DSP load */ - clock2 = utils::get_microseconds(); - const int64_t elapsed_time = clock2 - clock1; - _dsp_load = elapsed_time / (float)nomial_time; + m_dsp_calc.set_stop_timestamp_us (utils::get_microseconds()); + _dsp_load = m_dsp_calc.get_dsp_load(); - max_elapsed_us = std::max(elapsed_time, max_elapsed_us); - min_elapsed_us = std::min(elapsed_time, min_elapsed_us); + DEBUG_TIMING(string_compose("DSP Load: %1\n", _dsp_load)); + + max_elapsed_us = std::max(m_dsp_calc.elapsed_time_us(), max_elapsed_us); + min_elapsed_us = std::min(m_dsp_calc.elapsed_time_us(), min_elapsed_us); if ((m_cycle_count % 1000) == 0) { DEBUG_TIMING(string_compose("Elapsed process time(usecs) max: %1, min: %2\n", max_elapsed_us, diff --git a/libs/backends/portaudio/portaudio_backend.h b/libs/backends/portaudio/portaudio_backend.h index b9e1e600ba..15f32befc2 100644 --- a/libs/backends/portaudio/portaudio_backend.h +++ b/libs/backends/portaudio/portaudio_backend.h @@ -35,6 +35,7 @@ #include "portaudio_io.h" #include "winmmemidi_io.h" #include "cycle_timer.h" +#include "dsp_load_calculator.h" namespace ARDOUR { @@ -338,6 +339,8 @@ class PortAudioBackend : public AudioBackend { bool _freewheeling; bool _measure_latency; + DSPLoadCalculator m_dsp_calc; + uint64_t m_cycle_count; uint64_t m_total_deviation_us; uint64_t m_max_deviation_us;