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

Starts building out higher-level run_until functionality.

Specifically: you can now run until the next set of speaker samples has been delivered.
This commit is contained in:
Thomas Harte 2020-01-20 12:12:23 -05:00
parent 8349005c4b
commit cb61e84868
4 changed files with 53 additions and 6 deletions

View File

@ -53,7 +53,7 @@ void MultiSpeaker::speaker_did_complete_samples(Speaker *speaker, const std::vec
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
if(speaker != front_speaker_) return;
}
delegate_->speaker_did_complete_samples(this, buffer);
did_complete_samples(this, buffer);
}
void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {

View File

@ -45,17 +45,57 @@ class Machine {
virtual std::string debug_type() { return ""; }
/// Runs the machine for @c duration seconds.
void run_for(Time::Seconds duration) {
virtual void run_for(Time::Seconds duration) {
const double cycles = (duration * clock_rate_) + clock_conversion_error_;
clock_conversion_error_ = std::fmod(cycles, 1.0);
run_for(Cycles(static_cast<int>(cycles)));
}
/// Runs for the machine for at least @c duration seconds, and then until @c condition is true.
void run_until(Time::Seconds minimum_duration, std::function<bool()> condition) {
/*!
Runs for the machine for at least @c duration seconds, and then until @c condition is true.
@returns The amount of time run for.
*/
Time::Seconds run_until(Time::Seconds minimum_duration, std::function<bool()> condition) {
Time::Seconds total_runtime = minimum_duration;
run_for(minimum_duration);
while(!condition()) {
// Advance in increments of one 500th of a second until the condition
// is true; that's 1/10th of a 50Hz frame, but more like 1/8.33 of a
// 60Hz frame. Though most machines aren't exactly 50Hz or 60Hz, and some
// are arbitrary other refresh rates. So those observations are merely
// for scale.
run_for(0.002);
total_runtime += 0.002;
}
return total_runtime;
}
enum class MachineEvent {
/// At least one new packet of audio has been delivered to the spaker's delegate.
NewSpeakerSamplesGenerated
};
/*!
Runs for at least @c duration seconds, and then until @c event has occurred at least once since this
call to @c run_until_event.
@returns The amount of time run for.
*/
Time::Seconds run_until(Time::Seconds minimum_duration, MachineEvent event) {
switch(event) {
case MachineEvent::NewSpeakerSamplesGenerated: {
const auto speaker = get_speaker();
if(!speaker) {
run_for(minimum_duration);
return minimum_duration;
}
const int sample_sets = speaker->completed_sample_sets();
return run_until(minimum_duration, [sample_sets, speaker]() {
return speaker->completed_sample_sets() != sample_sets;
});
} break;
}
}

View File

@ -134,7 +134,7 @@ template <typename T> class LowpassSpeaker: public Speaker {
// announce to delegate if full
if(output_buffer_pointer_ == output_buffer_.size()) {
output_buffer_pointer_ = 0;
delegate_->speaker_did_complete_samples(this, output_buffer_);
did_complete_samples(this, output_buffer_);
}
cycles_remaining -= cycles_to_read;
@ -159,7 +159,7 @@ template <typename T> class LowpassSpeaker: public Speaker {
// Announce to delegate if full.
if(output_buffer_pointer_ == output_buffer_.size()) {
output_buffer_pointer_ = 0;
delegate_->speaker_did_complete_samples(this, output_buffer_);
did_complete_samples(this, output_buffer_);
}
// If the next loop around is going to reuse some of the samples just collected, use a memmove to

View File

@ -26,6 +26,8 @@ class Speaker {
virtual float get_ideal_clock_rate_in_range(float minimum, float maximum) = 0;
virtual void set_output_rate(float cycles_per_second, int buffer_size) = 0;
int completed_sample_sets() { return completed_sample_sets_; }
struct Delegate {
virtual void speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) = 0;
virtual void speaker_did_change_input_clock(Speaker *speaker) {}
@ -35,7 +37,12 @@ class Speaker {
}
protected:
void did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) {
++completed_sample_sets_;
delegate_->speaker_did_complete_samples(this, buffer);
}
Delegate *delegate_ = nullptr;
int completed_sample_sets_ = 0;
};
}