mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-28 09:54:49 +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_);
|
std::lock_guard<std::mutex> lock_guard(front_speaker_mutex_);
|
||||||
if(speaker != front_speaker_) return;
|
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) {
|
void MultiSpeaker::speaker_did_change_input_clock(Speaker *speaker) {
|
||||||
|
@ -45,17 +45,57 @@ class Machine {
|
|||||||
virtual std::string debug_type() { return ""; }
|
virtual std::string debug_type() { return ""; }
|
||||||
|
|
||||||
/// Runs the machine for @c duration seconds.
|
/// 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_;
|
const double cycles = (duration * clock_rate_) + clock_conversion_error_;
|
||||||
clock_conversion_error_ = std::fmod(cycles, 1.0);
|
clock_conversion_error_ = std::fmod(cycles, 1.0);
|
||||||
run_for(Cycles(static_cast<int>(cycles)));
|
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);
|
run_for(minimum_duration);
|
||||||
while(!condition()) {
|
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);
|
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
|
// announce to delegate if full
|
||||||
if(output_buffer_pointer_ == output_buffer_.size()) {
|
if(output_buffer_pointer_ == output_buffer_.size()) {
|
||||||
output_buffer_pointer_ = 0;
|
output_buffer_pointer_ = 0;
|
||||||
delegate_->speaker_did_complete_samples(this, output_buffer_);
|
did_complete_samples(this, output_buffer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
cycles_remaining -= cycles_to_read;
|
cycles_remaining -= cycles_to_read;
|
||||||
@ -159,7 +159,7 @@ template <typename T> class LowpassSpeaker: public Speaker {
|
|||||||
// Announce to delegate if full.
|
// Announce to delegate if full.
|
||||||
if(output_buffer_pointer_ == output_buffer_.size()) {
|
if(output_buffer_pointer_ == output_buffer_.size()) {
|
||||||
output_buffer_pointer_ = 0;
|
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
|
// 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 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;
|
virtual void set_output_rate(float cycles_per_second, int buffer_size) = 0;
|
||||||
|
|
||||||
|
int completed_sample_sets() { return completed_sample_sets_; }
|
||||||
|
|
||||||
struct Delegate {
|
struct Delegate {
|
||||||
virtual void speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) = 0;
|
virtual void speaker_did_complete_samples(Speaker *speaker, const std::vector<int16_t> &buffer) = 0;
|
||||||
virtual void speaker_did_change_input_clock(Speaker *speaker) {}
|
virtual void speaker_did_change_input_clock(Speaker *speaker) {}
|
||||||
@ -35,7 +37,12 @@ class Speaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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;
|
Delegate *delegate_ = nullptr;
|
||||||
|
int completed_sample_sets_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user