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;