mirror of
https://github.com/TomHarte/CLK.git
synced 2025-02-05 21:32:55 +00:00
Promote stereo status to template parameter.
This commit is contained in:
parent
48be7c677e
commit
a4a983eb81
@ -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_;
|
||||||
|
@ -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_;
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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_;
|
||||||
|
@ -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_;
|
||||||
|
@ -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_;
|
||||||
|
@ -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_;
|
||||||
|
@ -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:
|
||||||
|
@ -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.
|
||||||
|
@ -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];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user