1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00

Reintroduce mono to stereo conversion.

This commit is contained in:
Thomas Harte 2024-02-10 21:53:12 -05:00
parent 25085cb5af
commit 3a208460e2
2 changed files with 34 additions and 23 deletions

View File

@ -49,8 +49,10 @@ template <typename... T> class CompoundSource:
private: private:
template <typename... S> class CompoundSourceHolder { template <typename... S> class CompoundSourceHolder {
public: public:
template <bool output_stereo> void get_samples(std::size_t number_of_samples, std::int16_t *target) { template <bool output_stereo>
std::fill(target, target + number_of_samples, 0); void get_samples(std::size_t number_of_samples, typename SampleT<output_stereo>::type *target) {
// Default-construct all samples, to fill with silence.
std::fill(target, target + number_of_samples, typename SampleT<output_stereo>::type());
} }
void set_scaled_volume_range(int16_t, double *, double) {} void set_scaled_volume_range(int16_t, double *, double) {}
@ -73,9 +75,27 @@ template <typename... T> class CompoundSource:
static constexpr bool is_stereo = S::is_stereo || CompoundSourceHolder<R...>::is_stereo; static constexpr bool is_stereo = S::is_stereo || CompoundSourceHolder<R...>::is_stereo;
// TODO: fix below for potential stereo -> mono conversion.
template <bool output_stereo> template <bool output_stereo>
void get_samples(std::size_t number_of_samples, typename SampleT<output_stereo>::type *target) { void get_samples(std::size_t number_of_samples, typename ::Outputs::Speaker::SampleT<output_stereo>::type *target) {
// If this is the step at which a mono-to-stereo adaptation happens, apply it.
if constexpr (output_stereo && !S::is_stereo) {
// There'll be only one place in the chain that this conversion happens, but it'll
// happen there often. So avoid continuously reallocating.
if(conversion_source_.size() < number_of_samples) {
conversion_source_.resize(number_of_samples);
}
// Populate the conversion buffer with this source and all below.
get_samples<false>(number_of_samples, conversion_source_.data());
// Map up and return.
for(std::size_t c = 0; c < number_of_samples; c++) {
target[c].left = target[c].right = conversion_source_[c];
}
return;
}
// Get the rest of the output. // Get the rest of the output.
next_source_.template get_samples<output_stereo>(number_of_samples, target); next_source_.template get_samples<output_stereo>(number_of_samples, target);
@ -87,24 +107,12 @@ template <typename... T> class CompoundSource:
} }
// Get this component's output. // Get this component's output.
auto buffer_size = number_of_samples * (output_stereo ? 2 : 1); typename SampleT<output_stereo>::type local_samples[number_of_samples];
typename SampleT<is_stereo>::type local_samples[number_of_samples];
source_.get_samples(number_of_samples, local_samples); source_.get_samples(number_of_samples, local_samples);
// Merge it in; furthermore if total output is stereo but this source isn't, // Merge it in.
// map it to stereo. while(number_of_samples--) {
if constexpr (output_stereo == S::is_stereo) { target[number_of_samples] += local_samples[number_of_samples];
while(buffer_size--) {
target[buffer_size] += local_samples[buffer_size];
}
} else {
// This will happen only if mapping from mono to stereo, never in the
// other direction, because the compound source outputs stereo if any
// subcomponent does. So it outputs mono only if no stereo devices are
// in the mixing chain.
while(buffer_size--) {
target[buffer_size] += local_samples[buffer_size >> 1];
}
} }
// TODO: accelerate above? // TODO: accelerate above?
@ -132,9 +140,12 @@ template <typename... T> class CompoundSource:
private: private:
S &source_; S &source_;
CompoundSourceHolder<R...> next_source_; CompoundSourceHolder<R...> next_source_;
std::vector<MonoSample> conversion_source_;
}; };
public: public:
using Sample = typename SampleT<::Outputs::Speaker::is_stereo<T...>()>::type;
// To ensure at most one mono to stereo conversion, require appropriate source ordering. // To ensure at most one mono to stereo conversion, require appropriate source ordering.
static_assert(are_properly_ordered<T...>(), "Sources should be listed with all stereo sources before all mono sources"); static_assert(are_properly_ordered<T...>(), "Sources should be listed with all stereo sources before all mono sources");
@ -146,7 +157,7 @@ template <typename... T> class CompoundSource:
} }
} }
void get_samples(std::size_t number_of_samples, typename SampleT<::Outputs::Speaker::is_stereo<T...>()>::type *target) { void get_samples(std::size_t number_of_samples, Sample *target) {
source_holder_.template get_samples<::Outputs::Speaker::is_stereo<T...>()>(number_of_samples, target); source_holder_.template get_samples<::Outputs::Speaker::is_stereo<T...>()>(number_of_samples, target);
} }

View File

@ -17,9 +17,9 @@ namespace Outputs::Speaker {
using MonoSample = int16_t; using MonoSample = int16_t;
struct StereoSample { struct StereoSample {
#if TARGET_RT_BIG_ENDIAN #if TARGET_RT_BIG_ENDIAN
int16_t right, left; int16_t right = 0, left = 0;
#else #else
int16_t left, right; int16_t left = 0, right = 0;
#endif #endif
StereoSample() = default; StereoSample() = default;