1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-09 17:29:36 +00:00

Clean up SampleSource's getters.

This commit is contained in:
Thomas Harte 2024-02-01 21:29:00 -05:00
parent b28e3eb419
commit ce0d53b277
12 changed files with 77 additions and 80 deletions

View File

@ -28,7 +28,7 @@ class AudioGenerator: public ::Outputs::Speaker::SampleSource {
void get_samples(std::size_t number_of_samples, int16_t *target);
void skip_samples(std::size_t number_of_samples);
void set_sample_volume_range(std::int16_t range);
static constexpr bool get_is_stereo() { return false; }
static constexpr bool is_stereo = false;
private:
Concurrency::AsyncTaskQueue<false> &audio_queue_;

View File

@ -66,7 +66,7 @@ enum class Personality {
This AY has an attached mono or stereo mixer.
*/
template <bool is_stereo> class AY38910: public ::Outputs::Speaker::SampleSource {
template <bool stereo> class AY38910: public ::Outputs::Speaker::SampleSource {
public:
/// Creates a new AY38910.
AY38910(Personality, Concurrency::AsyncTaskQueue<false> &);
@ -109,7 +109,7 @@ template <bool is_stereo> class AY38910: public ::Outputs::Speaker::SampleSource
void get_samples(std::size_t number_of_samples, int16_t *target);
bool is_zero_level() const;
void set_sample_volume_range(std::int16_t range);
static constexpr bool get_is_stereo() { return is_stereo; }
static constexpr bool is_stereo = stereo;
private:
Concurrency::AsyncTaskQueue<false> &task_queue_;

View File

@ -31,7 +31,7 @@ class SCC: public ::Outputs::Speaker::SampleSource {
/// As per ::SampleSource; provides audio output.
void get_samples(std::size_t number_of_samples, std::int16_t *target);
void set_sample_volume_range(std::int16_t range);
static constexpr bool get_is_stereo() { return false; }
static constexpr bool is_stereo = false;
/// Writes to the SCC.
void write(uint16_t address, uint8_t value);

View File

@ -30,7 +30,7 @@ class OPLL: public OPLBase<OPLL> {
// The OPLL is generally 'half' as loud as it's told to be. This won't strictly be true in
// rhythm mode, but it's correct for melodic output.
double get_average_output_peak() const { return 0.5; }
double average_output_peak() const { return 0.5; }
/// Reads from the OPL.
uint8_t read(uint16_t address);

View File

@ -31,7 +31,7 @@ class SN76489: public Outputs::Speaker::SampleSource {
void get_samples(std::size_t number_of_samples, std::int16_t *target);
bool is_zero_level() const;
void set_sample_volume_range(std::int16_t range);
static constexpr bool get_is_stereo() { return false; }
static constexpr bool is_stereo = false;
private:
int master_divider_ = 0;

View File

@ -53,7 +53,7 @@ class Audio: public ::Outputs::Speaker::SampleSource {
void get_samples(std::size_t number_of_samples, int16_t *target);
bool is_zero_level() const;
void set_sample_volume_range(std::int16_t range);
constexpr static bool get_is_stereo() { return false; }
constexpr static bool is_stereo = false;
private:
Concurrency::AsyncTaskQueue<false> &task_queue_;

View File

@ -28,7 +28,7 @@ class TIASound: public Outputs::Speaker::SampleSource {
// To satisfy ::SampleSource.
void get_samples(std::size_t number_of_samples, int16_t *target);
void set_sample_volume_range(std::int16_t range);
static constexpr bool get_is_stereo() { return false; }
static constexpr bool is_stereo = false;
private:
Concurrency::AsyncTaskQueue<false> &audio_queue_;

View File

@ -27,7 +27,7 @@ class SoundGenerator: public ::Outputs::Speaker::SampleSource {
void get_samples(std::size_t number_of_samples, int16_t *target);
void skip_samples(std::size_t number_of_samples);
void set_sample_volume_range(std::int16_t range);
static constexpr bool get_is_stereo() { return false; }
static constexpr bool is_stereo = false;
private:
Concurrency::AsyncTaskQueue<false> &audio_queue_;

View File

@ -37,7 +37,7 @@ class Audio: public Outputs::Speaker::SampleSource {
// MARK: - SampleSource.
void set_sample_volume_range(int16_t range);
static constexpr bool get_is_stereo() { return true; } // Dave produces stereo sound.
static constexpr bool is_stereo = true;
void get_samples(std::size_t number_of_samples, int16_t *target);
private:

View File

@ -22,62 +22,7 @@ namespace Outputs::Speaker {
*/
template <typename... T> class CompoundSource:
public Outputs::Speaker::SampleSource {
public:
CompoundSource(T &... sources) : source_holder_(sources...) {
// Default: give all sources equal volume.
const auto volume = 1.0 / double(source_holder_.size());
for(std::size_t c = 0; c < source_holder_.size(); ++c) {
volumes_.push_back(volume);
}
}
void get_samples(std::size_t number_of_samples, std::int16_t *target) {
source_holder_.template get_samples<get_is_stereo()>(number_of_samples, target);
}
void skip_samples(const std::size_t number_of_samples) {
source_holder_.skip_samples(number_of_samples);
}
/*!
Sets the total output volume of this CompoundSource.
*/
void set_sample_volume_range(int16_t range) {
volume_range_ = range;
push_volumes();
}
/*!
Sets the relative volumes of the various sources underlying this
compound. The caller should ensure that the number of items supplied
matches the number of sources and that the values in it sum to 1.0.
*/
void set_relative_volumes(const std::vector<double> &volumes) {
assert(volumes.size() == source_holder_.size());
volumes_ = volumes;
push_volumes();
average_output_peak_ = 1.0 / source_holder_.total_scale(volumes_.data());
}
/*!
@returns true if any of the sources owned by this CompoundSource is stereo.
*/
static constexpr bool get_is_stereo() { return CompoundSourceHolder<T...>::get_is_stereo(); }
/*!
@returns the average output peak given the sources owned by this CompoundSource and the
current relative volumes.
*/
double get_average_output_peak() const {
return average_output_peak_;
}
private:
void push_volumes() {
const double scale = source_holder_.total_scale(volumes_.data());
source_holder_.set_scaled_volume_range(volume_range_, volumes_.data(), scale);
}
template <typename... S> class CompoundSourceHolder: public Outputs::Speaker::SampleSource {
public:
template <bool output_stereo> void get_samples(std::size_t number_of_samples, std::int16_t *target) {
@ -90,9 +35,7 @@ template <typename... T> class CompoundSource:
return 0;
}
static constexpr bool get_is_stereo() {
return false;
}
static constexpr bool is_stereo = false;
double total_scale(double *) const {
return 0.0;
@ -121,7 +64,7 @@ template <typename... T> class CompoundSource:
// Merge it in; furthermore if total output is stereo but this source isn't,
// map it to stereo.
if constexpr (output_stereo == S::get_is_stereo()) {
if constexpr (output_stereo == S::is_stereo) {
while(buffer_size--) {
target[buffer_size] += local_samples[buffer_size];
}
@ -144,7 +87,7 @@ template <typename... T> class CompoundSource:
}
void set_scaled_volume_range(int16_t range, double *volumes, double scale) {
const auto scaled_range = volumes[0] / double(source_.get_average_output_peak()) * double(range) / scale;
const auto scaled_range = volumes[0] / double(source_.average_output_peak()) * double(range) / scale;
source_.set_sample_volume_range(int16_t(scaled_range));
next_source_.set_scaled_volume_range(range, &volumes[1], scale);
}
@ -153,12 +96,10 @@ template <typename... T> class CompoundSource:
return 1 + CompoundSourceHolder<R...>::size();
}
static constexpr bool get_is_stereo() {
return S::get_is_stereo() || CompoundSourceHolder<R...>::get_is_stereo();
}
static constexpr bool is_stereo = S::is_stereo || CompoundSourceHolder<R...>::is_stereo;
double total_scale(double *volumes) const {
return (volumes[0] / source_.get_average_output_peak()) + next_source_.total_scale(&volumes[1]);
return (volumes[0] / source_.average_output_peak()) + next_source_.total_scale(&volumes[1]);
}
private:
@ -166,6 +107,62 @@ template <typename... T> class CompoundSource:
CompoundSourceHolder<R...> next_source_;
};
public:
CompoundSource(T &... sources) : source_holder_(sources...) {
// Default: give all sources equal volume.
const auto volume = 1.0 / double(source_holder_.size());
for(std::size_t c = 0; c < source_holder_.size(); ++c) {
volumes_.push_back(volume);
}
}
void get_samples(std::size_t number_of_samples, std::int16_t *target) {
source_holder_.template get_samples<is_stereo>(number_of_samples, target);
}
void skip_samples(const std::size_t number_of_samples) {
source_holder_.skip_samples(number_of_samples);
}
/*!
Sets the total output volume of this CompoundSource.
*/
void set_sample_volume_range(int16_t range) {
volume_range_ = range;
push_volumes();
}
/*!
Sets the relative volumes of the various sources underlying this
compound. The caller should ensure that the number of items supplied
matches the number of sources and that the values in it sum to 1.0.
*/
void set_relative_volumes(const std::vector<double> &volumes) {
assert(volumes.size() == source_holder_.size());
volumes_ = volumes;
push_volumes();
average_output_peak_ = 1.0 / source_holder_.total_scale(volumes_.data());
}
/*!
@c true if any of the sources owned by this CompoundSource is stereo.
*/
static constexpr bool is_stereo = CompoundSourceHolder<T...>::is_stereo;
/*!
@returns the average output peak given the sources owned by this CompoundSource and the
current relative volumes.
*/
double average_output_peak() const {
return average_output_peak_;
}
private:
void push_volumes() {
const double scale = source_holder_.total_scale(volumes_.data());
source_holder_.set_scaled_volume_range(volume_range_, volumes_.data(), scale);
}
CompoundSourceHolder<T...> source_holder_;
std::vector<double> volumes_;
int16_t volume_range_ = 0;

View File

@ -348,7 +348,7 @@ template <bool is_stereo> class PushLowpass: public LowpassBase<PushLowpass<is_s
source of a high-frequency stream of audio which it filters down to a
lower-frequency output.
*/
template <typename SampleSource> class PullLowpass: public LowpassBase<PullLowpass<SampleSource>, SampleSource::get_is_stereo()> {
template <typename SampleSource> class PullLowpass: public LowpassBase<PullLowpass<SampleSource>, SampleSource::is_stereo> {
public:
PullLowpass(SampleSource &sample_source) : sample_source_(sample_source) {
// Propagate an initial volume level.
@ -362,7 +362,7 @@ template <typename SampleSource> class PullLowpass: public LowpassBase<PullLowpa
}
bool get_is_stereo() final {
return SampleSource::get_is_stereo();
return SampleSource::is_stereo;
}
/*!
@ -381,7 +381,7 @@ template <typename SampleSource> class PullLowpass: public LowpassBase<PullLowpa
}
private:
using BaseT = LowpassBase<PullLowpass<SampleSource>, SampleSource::get_is_stereo()>;
using BaseT = LowpassBase<PullLowpass<SampleSource>, SampleSource::is_stereo>;
friend BaseT;
using BaseT::process;
@ -400,7 +400,7 @@ template <typename SampleSource> class PullLowpass: public LowpassBase<PullLowpa
}
int get_scale() {
return int(65536.0 / sample_source_.get_average_output_peak());
return int(65536.0 / sample_source_.average_output_peak());
}
void get_samples(size_t length, int16_t *target) {

View File

@ -54,7 +54,7 @@ class SampleSource {
/*!
Indicates whether this component will write stereo samples.
*/
static constexpr bool get_is_stereo() { return false; }
static constexpr bool is_stereo = false;
/*!
Permits a sample source to declare that, averaged over time, it will use only
@ -66,7 +66,7 @@ class SampleSource {
used by a speaker. If it varies, it should do so very infrequently and only to
represent changes in hardware configuration.
*/
double get_average_output_peak() const { return 1.0; }
double average_output_peak() const { return 1.0; }
};
}