mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-22 12:33:29 +00:00
Attempt an implementation of StretchedAudioSource
.
This commit is contained in:
parent
15b5a62e01
commit
17cad73177
@ -58,19 +58,65 @@ constexpr int MockingboardSlot = 4; // Conventional Mockingboard slot.
|
|||||||
// * ... and hence seven pixels per memory access window clock in high-res mode, 14 in double high-res, etc.
|
// * ... and hence seven pixels per memory access window clock in high-res mode, 14 in double high-res, etc.
|
||||||
constexpr float master_clock = 14318180.0;
|
constexpr float master_clock = 14318180.0;
|
||||||
|
|
||||||
template <typename SourceT>
|
/// Provides an audio source with will hold an instance of @c SourceT for audio generation, repeating one of its output samples
|
||||||
|
/// after every @c PacketClocks of output.
|
||||||
|
template <typename SourceT, std::size_t PacketClocks = 456>
|
||||||
class StretchedAudioSource {
|
class StretchedAudioSource {
|
||||||
public:
|
public:
|
||||||
|
template <typename... Args>
|
||||||
|
StretchedAudioSource(Args &&... args) : source_(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
void get_samples(std::size_t number_of_samples, int16_t *target) {
|
void get_samples(std::size_t number_of_samples, int16_t *target) {
|
||||||
// Approach should look something like — assuming a fully digital source_:
|
// Possible: the sample to duplicate fell exactly at the end of the last batch.
|
||||||
|
if(!remaining_packet_) {
|
||||||
|
remaining_packet_ = PacketClocks;
|
||||||
|
if constexpr (source_.get_is_stero()) {
|
||||||
|
target[0] = carry[0];
|
||||||
|
target[1] = carry[1];
|
||||||
|
target += 2;
|
||||||
|
} else {
|
||||||
|
target[0] = carry[0];
|
||||||
|
++target;
|
||||||
|
}
|
||||||
|
--number_of_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Divide required input into groups of PacketClocks samples; get all of those
|
||||||
|
// from the underlying source and then duplicate the final one.
|
||||||
//
|
//
|
||||||
// (1) sample_offset_ is always kept in the range [0, 912);
|
// Duplicating into the current output packet won't be possible if it happens
|
||||||
// (2) break down sample generation into 912-cycle blocks, getting the underlying source to provide
|
// to line up exactly with the end of the PacketClocks, in which case hold a copy
|
||||||
// the first 910 samples in each, then duplicate the final two.
|
// of the last level output in `carry` until next time.
|
||||||
//
|
while(number_of_samples) {
|
||||||
// (possibly subject to an appropriate divider, with 'by two' being the obvious potential choice)
|
const auto target_length = std::min(number_of_samples, remaining_packet_);
|
||||||
(void)number_of_samples;
|
source_.get_samples(target_length, target);
|
||||||
(void)target;
|
|
||||||
|
target += target_length * (1 + source_.get_is_stero());
|
||||||
|
number_of_samples -= target_length;
|
||||||
|
remaining_packet_ -= target_length;
|
||||||
|
|
||||||
|
if(!remaining_packet_) {
|
||||||
|
if(number_of_samples) {
|
||||||
|
remaining_packet_ = PacketClocks;
|
||||||
|
|
||||||
|
if constexpr (source_.get_is_stero()) {
|
||||||
|
target[0] = target[-2];
|
||||||
|
target[1] = target[-1];
|
||||||
|
target += 2;
|
||||||
|
} else {
|
||||||
|
target[0] = target[-1];
|
||||||
|
++target;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if constexpr (source_.get_is_stero()) {
|
||||||
|
carry[0] = target[-2];
|
||||||
|
carry[1] = target[-1];
|
||||||
|
} else {
|
||||||
|
carry[0] = target[-1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct passthroughs.
|
// Direct passthroughs.
|
||||||
@ -82,9 +128,9 @@ class StretchedAudioSource {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
SourceT source_;
|
SourceT source_;
|
||||||
std::size_t sample_offset_ = 0;
|
|
||||||
|
|
||||||
static constexpr std::size_t clock_length = 7;
|
std::size_t remaining_packet_ = PacketClocks;
|
||||||
|
std::array<uint16_t, 2> carry;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user