mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Clean up SampleSource's getters.
This commit is contained in:
parent
b28e3eb419
commit
ce0d53b277
@ -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_;
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
@ -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_;
|
||||
|
@ -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_;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user