mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Substitutes a more efficient inner loop for audio generation.
This commit is contained in:
parent
22ee51c12c
commit
b9a34bee51
@ -12,7 +12,8 @@ using namespace Apple::Macintosh;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// The sample_length is coupled with the clock rate selected within the Macintosh proper.
|
// The sample_length is coupled with the clock rate selected within the Macintosh proper;
|
||||||
|
// as per the header-declaration a divide-by-two clock is expected to arrive here.
|
||||||
const std::size_t sample_length = 352 / 2;
|
const std::size_t sample_length = 352 / 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -36,6 +37,7 @@ void Audio::set_volume(int volume) {
|
|||||||
// Post the volume change as a deferred event.
|
// Post the volume change as a deferred event.
|
||||||
task_queue_.defer([=] () {
|
task_queue_.defer([=] () {
|
||||||
volume_ = volume;
|
volume_ = volume;
|
||||||
|
set_volume_multiplier();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +49,7 @@ void Audio::set_enabled(bool on) {
|
|||||||
// Post the enabled mask change as a deferred event.
|
// Post the enabled mask change as a deferred event.
|
||||||
task_queue_.defer([=] () {
|
task_queue_.defer([=] () {
|
||||||
enabled_mask_ = int(on);
|
enabled_mask_ = int(on);
|
||||||
|
set_volume_multiplier();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +61,12 @@ bool Audio::is_zero_level() {
|
|||||||
|
|
||||||
void Audio::set_sample_volume_range(std::int16_t range) {
|
void Audio::set_sample_volume_range(std::int16_t range) {
|
||||||
// Some underflow here doesn't really matter.
|
// Some underflow here doesn't really matter.
|
||||||
volume_multiplier_ = range / (7 * 255);
|
output_volume_ = range / (7 * 255);
|
||||||
|
set_volume_multiplier();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::set_volume_multiplier() {
|
||||||
|
volume_multiplier_ = int16_t(output_volume_ * volume_ * enabled_mask_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
|
void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
|
||||||
@ -66,14 +74,24 @@ void Audio::get_samples(std::size_t number_of_samples, int16_t *target) {
|
|||||||
// in fact it uses pulse-width modulation. But the scale for pulses isn't specified, so
|
// in fact it uses pulse-width modulation. But the scale for pulses isn't specified, so
|
||||||
// that's something to return to.
|
// that's something to return to.
|
||||||
|
|
||||||
// TODO: temporary implementation. Very inefficient. Replace.
|
while(number_of_samples) {
|
||||||
for(std::size_t sample = 0; sample < number_of_samples; ++sample) {
|
// Determine how many output samples will be at the same level.
|
||||||
target[sample] = volume_multiplier_ * int16_t(sample_queue_.buffer[sample_queue_.read_pointer] * volume_ * enabled_mask_);
|
const auto cycles_left_in_sample = std::min(number_of_samples, sample_length - subcycle_offset_);
|
||||||
++subcycle_offset_;
|
|
||||||
|
|
||||||
if(subcycle_offset_ == sample_length) {
|
// Determine the output level, and output that many samples.
|
||||||
subcycle_offset_ = 0;
|
// (Hoping that the copiler substitutes an effective memset16-type operation here).
|
||||||
sample_queue_.read_pointer = (sample_queue_.read_pointer + 1) % sample_queue_.buffer.size();
|
const int16_t output_level = volume_multiplier_ * (int16_t(sample_queue_.buffer[sample_queue_.read_pointer]) - 128);
|
||||||
}
|
for(size_t c = 0; c < cycles_left_in_sample; ++c) {
|
||||||
|
target[c] = output_level;
|
||||||
|
}
|
||||||
|
target += cycles_left_in_sample;
|
||||||
|
|
||||||
|
// Advance the sample pointer.
|
||||||
|
subcycle_offset_ += cycles_left_in_sample;
|
||||||
|
sample_queue_.read_pointer = (sample_queue_.read_pointer + (subcycle_offset_ / sample_length)) % sample_queue_.buffer.size();
|
||||||
|
subcycle_offset_ %= sample_length;
|
||||||
|
|
||||||
|
// Decreate the number of samples left to write.
|
||||||
|
number_of_samples -= cycles_left_in_sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,9 +75,11 @@ class Audio: public ::Outputs::Speaker::SampleSource {
|
|||||||
// thread only.
|
// thread only.
|
||||||
int volume_ = 0;
|
int volume_ = 0;
|
||||||
int enabled_mask_ = 0;
|
int enabled_mask_ = 0;
|
||||||
|
std::int16_t output_volume_ = 0;
|
||||||
|
|
||||||
std::int16_t volume_multiplier_ = 0;
|
std::int16_t volume_multiplier_ = 0;
|
||||||
std::size_t subcycle_offset_ = 0;
|
std::size_t subcycle_offset_ = 0;
|
||||||
|
void set_volume_multiplier();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user