From f4d8c04f3ca4d077d8c4c8cb86b50d9d708bad71 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 1 Feb 2024 21:56:33 -0500 Subject: [PATCH] Without yet much exposition, draft sample-by-sample interface. --- .../Speaker/Implementation/SampleSource.hpp | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/Outputs/Speaker/Implementation/SampleSource.hpp b/Outputs/Speaker/Implementation/SampleSource.hpp index c356530df..29dc70834 100644 --- a/Outputs/Speaker/Implementation/SampleSource.hpp +++ b/Outputs/Speaker/Implementation/SampleSource.hpp @@ -15,8 +15,8 @@ namespace Outputs::Speaker { template struct SampleT; -template <> struct SampleT { using type = std::array; }; -template <> struct SampleT { using type = std::uint16_t; }; +template <> struct SampleT { using type = std::array; }; +template <> struct SampleT { using type = std::int16_t; }; /*! A sample source is something that can provide a stream of audio. @@ -26,10 +26,28 @@ template <> struct SampleT { using type = std::uint16_t; }; template class SampleSource { public: + /*! + Indicates whether this component will write stereo samples. + */ + static constexpr bool is_stereo = SourceT::is_stereo; + /*! Should write the next @c number_of_samples to @c target. */ - void get_samples([[maybe_unused]] std::size_t number_of_samples, [[maybe_unused]] std::int16_t *target) {} + void get_samples(std::size_t number_of_samples, std::int16_t *target) { + const auto &source = *static_cast(this); + while(number_of_samples--) { + if constexpr (is_stereo) { + const auto next = source.level(); + target[0] = next[0]; + target[1] = next[1]; + target += 2; + } else { + *target = source.level(); + ++target; + } + } + } /*! Should skip the next @c number_of_samples. Subclasses of this SampleSource @@ -38,6 +56,9 @@ class SampleSource { implementation below. */ void skip_samples(const std::size_t number_of_samples) { + if constexpr (&SourceT::advance == &SampleSource::advance) { + return; + } std::int16_t scratch_pad[number_of_samples]; get_samples(number_of_samples, scratch_pad); } @@ -47,9 +68,17 @@ class SampleSource { fill the target with zeroes; @c false if a call might return all zeroes or might not. */ - bool is_zero_level() const { - return false; + bool is_zero_level() const { return false; } + auto level() const { + typename SampleT::type result; + if constexpr (is_stereo) { + result[0] = result[1] = 0; + } else { + result = 0; + } + return result; } + void advance() {} /*! Sets the proper output range for this sample source; it should write values @@ -57,11 +86,6 @@ class SampleSource { */ void set_sample_volume_range([[maybe_unused]] std::int16_t volume) {} - /*! - Indicates whether this component will write stereo samples. - */ - static constexpr bool is_stereo = SourceT::is_stereo; - /*! Permits a sample source to declare that, averaged over time, it will use only a certain proportion of the allocated volume range. This commonly happens