mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 00:37:27 +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:
parent
8349005c4b
commit
cb61e84868
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user