mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 18:30:21 +00:00
In theory provides a full implementation of audio.
Albeit seemingly ineffective.
This commit is contained in:
parent
17635da812
commit
5c08bb810e
@ -11,7 +11,7 @@
|
||||
using namespace Apple::Macintosh;
|
||||
|
||||
namespace {
|
||||
const HalfCycles sample_length(704);
|
||||
const std::size_t sample_length = 352;
|
||||
}
|
||||
|
||||
Audio::Audio(Concurrency::DeferringAsyncTaskQueue &task_queue) : task_queue_(task_queue) {}
|
||||
@ -52,13 +52,50 @@ bool Audio::is_zero_level() {
|
||||
|
||||
void Audio::set_sample_volume_range(std::int16_t range) {
|
||||
// Some underflow here doesn't really matter.
|
||||
volume_multiplier_ = range / 7;
|
||||
volume_multiplier_ = range / (7 * 255);
|
||||
}
|
||||
|
||||
void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
|
||||
// TODO.
|
||||
const auto write_pointer = sample_queue_.write_pointer.load();
|
||||
auto read_pointer = sample_queue_.read_pointer.load();
|
||||
|
||||
// TODO: the implementation below acts as if the hardware uses pulse-amplitude modulation;
|
||||
// in fact it uses pulse-width modulation. But the scale for pulses isn't specified, so
|
||||
// that's something to return to.
|
||||
|
||||
// TODO: temporary implementation. Very inefficient. Replace.
|
||||
while(number_of_samples--) {
|
||||
*target = volume_multiplier_ * int16_t(sample_queue_.buffer[read_pointer] * volume_ * enabled_mask_);
|
||||
++target;
|
||||
++subcycle_offset_;
|
||||
|
||||
if(subcycle_offset_ == sample_length) {
|
||||
// printf("%d: %d\n", sample_queue_.buffer[read_pointer], volume_multiplier_ * sample_queue_.buffer[read_pointer] * volume_ * enabled_mask_);
|
||||
subcycle_offset_ = 0;
|
||||
const unsigned int next_read_pointer = (read_pointer + 1) % sample_queue_.buffer.size();
|
||||
if(next_read_pointer != write_pointer) {
|
||||
read_pointer = next_read_pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sample_queue_.read_pointer.store(read_pointer);
|
||||
}
|
||||
|
||||
void Audio::skip_samples(std::size_t number_of_samples) {
|
||||
// TODO.
|
||||
const auto write_pointer = sample_queue_.write_pointer.load();
|
||||
auto read_pointer = sample_queue_.read_pointer.load();
|
||||
|
||||
// Number of samples that would be consumed is (number_of_samples + subcycle_offset_) / sample_length.
|
||||
const unsigned int samples_passed = static_cast<unsigned int>((number_of_samples + subcycle_offset_) / sample_length);
|
||||
subcycle_offset_ = (number_of_samples + subcycle_offset_) % sample_length;
|
||||
|
||||
// Get also number of samples available.
|
||||
const unsigned int samples_available = static_cast<unsigned int>((write_pointer + sample_queue_.buffer.size() - read_pointer) % sample_queue_.buffer.size());
|
||||
|
||||
// Advance by whichever of those is the lower number.
|
||||
const auto samples_to_consume = std::min(samples_available, samples_passed);
|
||||
read_pointer = (read_pointer + samples_to_consume) % sample_queue_.buffer.size();
|
||||
|
||||
sample_queue_.read_pointer.store(read_pointer);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ class Audio: public ::Outputs::Speaker::SampleSource {
|
||||
|
||||
std::int16_t volume_multiplier_ = 0;
|
||||
|
||||
HalfCycles subcycle_offset_;
|
||||
std::size_t subcycle_offset_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -340,6 +340,10 @@ class ConcreteMachine:
|
||||
if(port == Port::B && line == Line::Two) keyboard_.set_input(value);
|
||||
}
|
||||
|
||||
void run_for(HalfCycles duration) {
|
||||
audio_.time_since_update += duration;
|
||||
}
|
||||
|
||||
private:
|
||||
ConcreteMachine &machine_;
|
||||
RealTimeClock &clock_;
|
||||
|
Loading…
Reference in New Issue
Block a user