audio: master-clock playback timing, output clock compensation, buffer config, interpolated speed

- playback timer uses the audio output device as its master clock: the
  PortAudio callback counts consumed frames (including underrun
  zero-fill) so video cannot drift away from what is heard; wall clock
  remains as fallback when no clocked output is running
- output clock compensates for device output latency; new Preferences >
  Audio buffer size setting (0 = auto)
- SampleBuffer::speed() now uses linear interpolation instead of
  nearest-neighbor sampling
- regression tests: audio-clock driven timer (fwd/rev/speed), wall
  clock fallback, interpolation correctness
This commit is contained in:
2026-07-19 21:44:34 +08:00
parent 0c02ff0d77
commit a7ddc0f114
16 changed files with 266 additions and 8 deletions
+1
View File
@@ -87,6 +87,7 @@ void PreviewAudioDevice::clear()
buffer_.clear();
bytes_read_ = 0;
output_frames_consumed_.store(0);
}
}
+25
View File
@@ -24,6 +24,8 @@
#include <olive/core/render/audioparams.h>
#include <atomic>
#include "previewautocacher.h"
namespace olive
@@ -66,6 +68,27 @@ public:
void clear();
/**
* @brief Frames consumed by the audio output callback
*
* Counted in the callback itself so underrun (zero-filled) frames are
* included, making the value usable as a playback clock.
*/
void add_output_frames(qint64 frame_count)
{
output_frames_consumed_.fetch_add(frame_count);
}
qint64 output_frames_consumed() const
{
return output_frames_consumed_.load();
}
void reset_output_frames()
{
output_frames_consumed_.store(0);
}
signals:
void notify();
@@ -79,6 +102,8 @@ private:
qint64 notify_interval_;
qint64 bytes_read_;
std::atomic<qint64> output_frames_consumed_{0};
};
}