1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-26 10:29:31 +00:00

Promote stereo status to template parameter.

This commit is contained in:
Thomas Harte 2024-02-08 15:21:47 -05:00
parent 48be7c677e
commit a4a983eb81
14 changed files with 20 additions and 36 deletions

View File

@ -17,7 +17,7 @@
namespace MOS::MOS6560 { namespace MOS::MOS6560 {
// audio state // audio state
class AudioGenerator: public ::Outputs::Speaker::SampleSource<AudioGenerator> { class AudioGenerator: public ::Outputs::Speaker::SampleSource<AudioGenerator, false> {
public: public:
AudioGenerator(Concurrency::AsyncTaskQueue<false> &audio_queue); AudioGenerator(Concurrency::AsyncTaskQueue<false> &audio_queue);
@ -28,7 +28,6 @@ class AudioGenerator: public ::Outputs::Speaker::SampleSource<AudioGenerator> {
void get_samples(std::size_t number_of_samples, int16_t *target); void get_samples(std::size_t number_of_samples, int16_t *target);
void skip_samples(std::size_t number_of_samples); void skip_samples(std::size_t number_of_samples);
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
static constexpr bool is_stereo = false;
private: private:
Concurrency::AsyncTaskQueue<false> &audio_queue_; Concurrency::AsyncTaskQueue<false> &audio_queue_;

View File

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

View File

@ -16,14 +16,13 @@ namespace Audio {
/*! /*!
Provides a sample source that can programmatically be set to one of two values. Provides a sample source that can programmatically be set to one of two values.
*/ */
class Toggle: public Outputs::Speaker::SampleSource<Toggle> { class Toggle: public Outputs::Speaker::SampleSource<Toggle, false> {
public: public:
Toggle(Concurrency::AsyncTaskQueue<false> &audio_queue); Toggle(Concurrency::AsyncTaskQueue<false> &audio_queue);
void get_samples(std::size_t number_of_samples, std::int16_t *target); void get_samples(std::size_t number_of_samples, std::int16_t *target);
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
void skip_samples(const std::size_t number_of_samples); void skip_samples(const std::size_t number_of_samples);
static constexpr bool is_stereo = false;
void set_output(bool enabled); void set_output(bool enabled);
bool get_output() const; bool get_output() const;

View File

@ -20,7 +20,7 @@ namespace Konami {
and five channels of output. The original SCC uses the same wave for channels and five channels of output. The original SCC uses the same wave for channels
four and five, the SCC+ supports different waves for the two channels. four and five, the SCC+ supports different waves for the two channels.
*/ */
class SCC: public ::Outputs::Speaker::SampleSource<SCC> { class SCC: public ::Outputs::Speaker::SampleSource<SCC, false> {
public: public:
/// Creates a new SCC. /// Creates a new SCC.
SCC(Concurrency::AsyncTaskQueue<false> &task_queue); SCC(Concurrency::AsyncTaskQueue<false> &task_queue);
@ -31,7 +31,6 @@ class SCC: public ::Outputs::Speaker::SampleSource<SCC> {
/// As per ::SampleSource; provides audio output. /// As per ::SampleSource; provides audio output.
void get_samples(std::size_t number_of_samples, std::int16_t *target); void get_samples(std::size_t number_of_samples, std::int16_t *target);
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
static constexpr bool is_stereo = false;
/// Writes to the SCC. /// Writes to the SCC.
void write(uint16_t address, uint8_t value); void write(uint16_t address, uint8_t value);

View File

@ -13,7 +13,7 @@
namespace Yamaha::OPL { namespace Yamaha::OPL {
template <typename Child> class OPLBase: public ::Outputs::Speaker::SampleSource<Child> { template <typename Child, bool stereo> class OPLBase: public ::Outputs::Speaker::SampleSource<Child, stereo> {
public: public:
void write(uint16_t address, uint8_t value) { void write(uint16_t address, uint8_t value) {
if(address & 1) { if(address & 1) {

View File

@ -19,7 +19,7 @@
namespace Yamaha::OPL { namespace Yamaha::OPL {
class OPLL: public OPLBase<OPLL> { class OPLL: public OPLBase<OPLL, false> {
public: public:
/// Creates a new OPLL or VRC7. /// Creates a new OPLL or VRC7.
OPLL(Concurrency::AsyncTaskQueue<false> &task_queue, int audio_divider = 1, bool is_vrc7 = false); OPLL(Concurrency::AsyncTaskQueue<false> &task_queue, int audio_divider = 1, bool is_vrc7 = false);
@ -27,7 +27,6 @@ class OPLL: public OPLBase<OPLL> {
/// As per ::SampleSource; provides audio output. /// As per ::SampleSource; provides audio output.
void get_samples(std::size_t number_of_samples, std::int16_t *target); void get_samples(std::size_t number_of_samples, std::int16_t *target);
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
static constexpr bool is_stereo = false;
// The OPLL is generally 'half' as loud as it's told to be. This won't strictly be true in // 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. // rhythm mode, but it's correct for melodic output.
@ -37,7 +36,7 @@ class OPLL: public OPLBase<OPLL> {
uint8_t read(uint16_t address); uint8_t read(uint16_t address);
private: private:
friend OPLBase<OPLL>; friend OPLBase<OPLL, false>;
void write_register(uint8_t address, uint8_t value); void write_register(uint8_t address, uint8_t value);
int audio_divider_ = 0; int audio_divider_ = 0;

View File

@ -13,7 +13,7 @@
namespace TI { namespace TI {
class SN76489: public Outputs::Speaker::SampleSource<SN76489> { class SN76489: public Outputs::Speaker::SampleSource<SN76489, false> {
public: public:
enum class Personality { enum class Personality {
SN76489, SN76489,
@ -31,7 +31,6 @@ class SN76489: public Outputs::Speaker::SampleSource<SN76489> {
void get_samples(std::size_t number_of_samples, std::int16_t *target); void get_samples(std::size_t number_of_samples, std::int16_t *target);
bool is_zero_level() const; bool is_zero_level() const;
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
static constexpr bool is_stereo = false;
private: private:
int master_divider_ = 0; int master_divider_ = 0;

View File

@ -16,7 +16,7 @@
namespace Apple::IIgs::Sound { namespace Apple::IIgs::Sound {
class GLU: public Outputs::Speaker::SampleSource<GLU> { class GLU: public Outputs::Speaker::SampleSource<GLU, false> { // TODO: isn't this stereo?
public: public:
GLU(Concurrency::AsyncTaskQueue<false> &audio_queue); GLU(Concurrency::AsyncTaskQueue<false> &audio_queue);
@ -37,7 +37,6 @@ class GLU: public Outputs::Speaker::SampleSource<GLU> {
void get_samples(std::size_t number_of_samples, std::int16_t *target); void get_samples(std::size_t number_of_samples, std::int16_t *target);
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
void skip_samples(const std::size_t number_of_samples); void skip_samples(const std::size_t number_of_samples);
static constexpr bool is_stereo = false;
private: private:
Concurrency::AsyncTaskQueue<false> &audio_queue_; Concurrency::AsyncTaskQueue<false> &audio_queue_;

View File

@ -23,7 +23,7 @@ namespace Apple::Macintosh {
Designed to be clocked at half the rate of the real hardware i.e. Designed to be clocked at half the rate of the real hardware i.e.
a shade less than 4Mhz. a shade less than 4Mhz.
*/ */
class Audio: public ::Outputs::Speaker::SampleSource<Audio> { class Audio: public ::Outputs::Speaker::SampleSource<Audio, false> {
public: public:
Audio(Concurrency::AsyncTaskQueue<false> &task_queue); Audio(Concurrency::AsyncTaskQueue<false> &task_queue);
@ -53,7 +53,6 @@ class Audio: public ::Outputs::Speaker::SampleSource<Audio> {
void get_samples(std::size_t number_of_samples, int16_t *target); void get_samples(std::size_t number_of_samples, int16_t *target);
bool is_zero_level() const; bool is_zero_level() const;
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
constexpr static bool is_stereo = false;
private: private:
Concurrency::AsyncTaskQueue<false> &task_queue_; Concurrency::AsyncTaskQueue<false> &task_queue_;

View File

@ -17,7 +17,7 @@ namespace Atari2600 {
// will give greater resolution to changes in audio state. 1, 2 and 19 are the only divisors of 38. // will give greater resolution to changes in audio state. 1, 2 and 19 are the only divisors of 38.
constexpr int CPUTicksPerAudioTick = 2; constexpr int CPUTicksPerAudioTick = 2;
class TIASound: public Outputs::Speaker::SampleSource<TIASound> { class TIASound: public Outputs::Speaker::SampleSource<TIASound, false> {
public: public:
TIASound(Concurrency::AsyncTaskQueue<false> &audio_queue); TIASound(Concurrency::AsyncTaskQueue<false> &audio_queue);
@ -28,7 +28,6 @@ class TIASound: public Outputs::Speaker::SampleSource<TIASound> {
// To satisfy ::SampleSource. // To satisfy ::SampleSource.
void get_samples(std::size_t number_of_samples, int16_t *target); void get_samples(std::size_t number_of_samples, int16_t *target);
void set_sample_volume_range(std::int16_t range); void set_sample_volume_range(std::int16_t range);
static constexpr bool is_stereo = false;
private: private:
Concurrency::AsyncTaskQueue<false> &audio_queue_; Concurrency::AsyncTaskQueue<false> &audio_queue_;

View File

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

View File

@ -26,7 +26,7 @@ enum class Interrupt: uint8_t {
/*! /*!
Models the audio-production subset of Dave's behaviour. Models the audio-production subset of Dave's behaviour.
*/ */
class Audio: public Outputs::Speaker::SampleSource<Audio> { class Audio: public Outputs::Speaker::SampleSource<Audio, true> {
public: public:
Audio(Concurrency::AsyncTaskQueue<false> &audio_queue); Audio(Concurrency::AsyncTaskQueue<false> &audio_queue);
@ -37,7 +37,6 @@ class Audio: public Outputs::Speaker::SampleSource<Audio> {
// MARK: - SampleSource. // MARK: - SampleSource.
void set_sample_volume_range(int16_t range); void set_sample_volume_range(int16_t range);
static constexpr bool is_stereo = true;
void get_samples(std::size_t number_of_samples, int16_t *target); void get_samples(std::size_t number_of_samples, int16_t *target);
private: private:

View File

@ -31,7 +31,7 @@ template <typename... S> constexpr bool is_stereo() {
An owner may optionally assign relative volumes. An owner may optionally assign relative volumes.
*/ */
template <typename... T> class CompoundSource: template <typename... T> class CompoundSource:
public Outputs::Speaker::SampleSource<CompoundSource<T...>> { public Outputs::Speaker::SampleSource<CompoundSource<T...>, ::Outputs::Speaker::is_stereo<T...>()> {
private: private:
template <typename... S> class CompoundSourceHolder { template <typename... S> class CompoundSourceHolder {
public: public:
@ -57,6 +57,8 @@ template <typename... T> class CompoundSource:
public: public:
CompoundSourceHolder(S &source, R &...next) : source_(source), next_source_(next...) {} CompoundSourceHolder(S &source, R &...next) : source_(source), next_source_(next...) {}
static constexpr bool is_stereo = S::is_stereo || CompoundSourceHolder<R...>::is_stereo;
template <bool output_stereo> void get_samples(std::size_t number_of_samples, std::int16_t *target) { template <bool output_stereo> void get_samples(std::size_t number_of_samples, std::int16_t *target) {
// 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);
@ -107,8 +109,6 @@ template <typename... T> class CompoundSource:
return 1 + CompoundSourceHolder<R...>::size(); return 1 + CompoundSourceHolder<R...>::size();
} }
static constexpr bool is_stereo = S::is_stereo || CompoundSourceHolder<R...>::is_stereo;
double total_scale(double *volumes) const { double total_scale(double *volumes) const {
return (volumes[0] / source_.average_output_peak()) + next_source_.total_scale(&volumes[1]); return (volumes[0] / source_.average_output_peak()) + next_source_.total_scale(&volumes[1]);
} }
@ -128,7 +128,7 @@ template <typename... T> class CompoundSource:
} }
void get_samples(std::size_t number_of_samples, std::int16_t *target) { void get_samples(std::size_t number_of_samples, std::int16_t *target) {
source_holder_.template get_samples<is_stereo>(number_of_samples, target); source_holder_.template get_samples<::Outputs::Speaker::is_stereo<T...>()>(number_of_samples, target);
} }
void skip_samples(const std::size_t number_of_samples) { void skip_samples(const std::size_t number_of_samples) {
@ -155,11 +155,6 @@ template <typename... T> class CompoundSource:
average_output_peak_ = 1.0 / source_holder_.total_scale(volumes_.data()); 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 = ::Outputs::Speaker::is_stereo<T...>();
/*! /*!
@returns the average output peak given the sources owned by this CompoundSource and the @returns the average output peak given the sources owned by this CompoundSource and the
current relative volumes. current relative volumes.

View File

@ -23,13 +23,13 @@ template <> struct SampleT<false> { using type = std::int16_t; };
This optional base class provides the interface expected to be exposed This optional base class provides the interface expected to be exposed
by the template parameter to LowpassSpeaker. by the template parameter to LowpassSpeaker.
*/ */
template <typename SourceT> template <typename SourceT, bool stereo>
class SampleSource { class SampleSource {
public: public:
/*! /*!
Indicates whether this component will write stereo samples. Indicates whether this component will write stereo samples.
*/ */
static constexpr bool is_stereo = SourceT::is_stereo; static constexpr bool is_stereo = stereo;
/*! /*!
Should write the next @c number_of_samples to @c target. Should write the next @c number_of_samples to @c target.
@ -56,7 +56,7 @@ class SampleSource {
implementation below. implementation below.
*/ */
void skip_samples(const std::size_t number_of_samples) { void skip_samples(const std::size_t number_of_samples) {
if constexpr (&SourceT::advance == &SampleSource<SourceT>::advance) { if constexpr (&SourceT::advance == &SampleSource<SourceT, stereo>::advance) {
return; return;
} }
std::int16_t scratch_pad[number_of_samples]; std::int16_t scratch_pad[number_of_samples];