1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-06-25 18:30:07 +00:00

Switch to int; attempt to do a better job of initial audio filling.

This commit is contained in:
Thomas Harte 2022-07-09 13:33:46 -04:00
parent 51ed3f2ed0
commit 6dabdaca45
20 changed files with 72 additions and 54 deletions

View File

@ -215,7 +215,7 @@ class ConcreteMachine:
mc68000_.run_for(cycles);
}
void flush_output(Output) final {
void flush_output(int) final {
chipset_.flush();
}

View File

@ -1049,9 +1049,9 @@ template <bool has_fdc> class ConcreteMachine:
}
/// Fields requests to pump all output.
void flush_output(Output output) final {
void flush_output(int outputs) final {
// Just flush the AY.
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
ay_.update();
ay_.flush();
}

View File

@ -810,13 +810,13 @@ template <Analyser::Static::AppleII::Target::Model model> class ConcreteMachine:
return Cycles(1);
}
void flush_output(Output output) final {
void flush_output(int outputs) final {
update_just_in_time_cards();
if(int(output) & int(Output::Video)) {
if(outputs & Output::Video) {
update_video();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -326,14 +326,14 @@ class ConcreteMachine:
m65816_.run_for(cycles);
}
void flush_output(Output output) final {
void flush_output(int outputs) final {
iwm_.flush();
adb_glu_.flush();
if(int(output) & int(Output::Video)) {
if(outputs & Output::Video) {
video_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
AudioUpdater updater(this);
audio_queue_.perform();
}

View File

@ -365,7 +365,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
return delay;
}
void flush_output(Output) {
void flush_output(int) {
// Flush the video before the audio queue; in a Mac the
// video is responsible for providing part of the
// audio signal, so the two aren't as distinct as in

View File

@ -174,7 +174,7 @@ class ConcreteMachine:
bus_->apply_confidence(confidence_counter_);
}
void flush_output(Output) final {
void flush_output(int) final {
bus_->flush();
}

View File

@ -413,16 +413,16 @@ class ConcreteMachine:
return HalfCycles(0);
}
void flush_output(Output output) final {
void flush_output(int outputs) final {
dma_.flush();
mfp_.flush();
keyboard_acia_.flush();
midi_acia_.flush();
if(int(output) & int(Output::Video)) {
if(outputs & Output::Video) {
video_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -342,11 +342,11 @@ class ConcreteMachine:
return penalty;
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
vdp_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -620,11 +620,11 @@ class ConcreteMachine:
return Cycles(1);
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
update_video();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
mos6560_.flush();
}
}

View File

@ -501,11 +501,11 @@ template <bool has_scsi_bus> class ConcreteMachine:
return Cycles(int(cycles));
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
video_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -539,11 +539,11 @@ template <bool has_disk_controller, bool is_6mhz> class ConcreteMachine:
return penalty;
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
nick_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -615,11 +615,11 @@ class ConcreteMachine:
return addition;
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
vdp_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -210,11 +210,11 @@ class ConcreteMachine:
z80_.run_for(cycles);
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
vdp_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -578,11 +578,11 @@ template <Analyser::Static::Oric::Target::DiskInterface disk_interface, CPU::MOS
return Cycles(1);
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
video_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
via_.flush();
}
diskii_.flush();

View File

@ -292,13 +292,13 @@ template<bool is_zx81> class ConcreteMachine:
return HalfCycles(0);
}
void flush_output(Output output) final {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) final {
if(outputs & Output::Video) {
video_.flush();
}
if constexpr (is_zx81) {
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -263,12 +263,12 @@ template<Model model> class ConcreteMachine:
}
}
void flush_output(Output output) override {
if(int(output) & int(Output::Video)) {
void flush_output(int outputs) override {
if(outputs & Output::Video) {
video_.flush();
}
if(int(output) & int(Output::Audio)) {
if(outputs & Output::Audio) {
update_audio();
audio_queue_.perform();
}

View File

@ -61,13 +61,13 @@ class TimedMachine {
virtual float get_confidence() { return 0.5f; }
virtual std::string debug_type() { return ""; }
enum class Output {
Video = 1 << 0,
Audio = 1 << 1
struct Output {
static constexpr int Video = 1 << 0;
static constexpr int Audio = 1 << 1;
};
/// Ensures all locally-buffered output is posted onward for the types of output indicated
/// by the bitfield argument.
virtual void flush_output(Output) {}
/// by the bitfield argument, which is comprised of flags from the namespace @c Output.
virtual void flush_output(int) {}
protected:
/// Runs the machine for @c cycles.

View File

@ -58,4 +58,9 @@
*/
@property (nonatomic, readonly) NSUInteger preferredBufferSize;
/*!
@returns @C YES if this queue is running low or is completely exhausted of new audio buffers.
*/
@property (atomic, readonly) BOOL isRunningDry;
@end

View File

@ -8,6 +8,7 @@
#import "CSAudioQueue.h"
@import AudioToolbox;
#include <stdatomic.h>
#define AudioQueueBufferMaxLength 8192
#define NumberOfStoredAudioQueueBuffer 16
@ -29,7 +30,7 @@ static NSLock *CSAudioQueueDeallocLock;
AudioQueueRef _audioQueue;
NSLock *_storedBuffersLock;
CSWeakAudioQueuePointer *_weakPointer;
int _enqueuedBuffers;
atomic_int _enqueuedBuffers;
}
#pragma mark - AudioQueue callbacks
@ -39,14 +40,14 @@ static NSLock *CSAudioQueueDeallocLock;
*/
- (BOOL)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer {
[_storedBuffersLock lock];
--_enqueuedBuffers;
const int buffers = atomic_fetch_add(&_enqueuedBuffers, -1);
// If that leaves nothing in the queue, re-enqueue whatever just came back in order to keep the
// queue going. AudioQueues seem to stop playing and never restart no matter how much encouragement
// if exhausted.
if(!_enqueuedBuffers) {
if(!buffers) {
AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL);
++_enqueuedBuffers;
atomic_fetch_add(&_enqueuedBuffers, 1);
} else {
AudioQueueFreeBuffer(_audioQueue, buffer);
}
@ -71,6 +72,10 @@ static void audioOutputCallback(
}
}
- (BOOL)isRunningDry {
return atomic_load_explicit(&_enqueuedBuffers, memory_order_relaxed) < 2;
}
#pragma mark - Standard object lifecycle
- (instancetype)initWithSamplingRate:(Float64)samplingRate isStereo:(BOOL)isStereo {
@ -158,11 +163,11 @@ static void audioOutputCallback(
[_storedBuffersLock lock];
// Don't enqueue more than 4 buffers ahead of now, to ensure not too much latency accrues.
if(_enqueuedBuffers > 4) {
if(atomic_load_explicit(&_enqueuedBuffers, memory_order_relaxed) > 4) {
[_storedBuffersLock unlock];
return;
}
++_enqueuedBuffers;
atomic_fetch_add(&_enqueuedBuffers, 1);
AudioQueueBufferRef newBuffer;
AudioQueueAllocateBuffer(_audioQueue, (UInt32)bufferBytes * 2, &newBuffer);

View File

@ -678,13 +678,21 @@ struct ActivityObserver: public Activity::Observer {
- (void)audioQueueIsRunningDry:(nonnull CSAudioQueue *)audioQueue {
updater.update([self] {
updater.performer.machine->flush_output(MachineTypes::TimedMachine::Output::Audio);
updater.performer.machine->flush_output(MachineTypes::TimedMachine::Output::Audio);// | MachineTypes::TimedMachine::Output::Video);
// dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
// [self.view updateBacking];
// });
});
}
- (void)scanTargetViewDisplayLinkDidFire:(CSScanTargetView *)view now:(const CVTimeStamp *)now outputTime:(const CVTimeStamp *)outputTime {
updater.update([self] {
updater.performer.machine->flush_output(MachineTypes::TimedMachine::Output::Video);
auto outputs = MachineTypes::TimedMachine::Output::Video;
if(_audioQueue.isRunningDry) {
outputs |= MachineTypes::TimedMachine::Output::Audio;
}
updater.performer.machine->flush_output(outputs);
dispatch_async(dispatch_get_main_queue(), ^{
[self.view updateBacking];
[self.view draw];