mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-23 11:30:24 +00:00
Switch to int
; attempt to do a better job of initial audio filling.
This commit is contained in:
parent
51ed3f2ed0
commit
6dabdaca45
@ -215,7 +215,7 @@ class ConcreteMachine:
|
||||
mc68000_.run_for(cycles);
|
||||
}
|
||||
|
||||
void flush_output(Output) final {
|
||||
void flush_output(int) final {
|
||||
chipset_.flush();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -174,7 +174,7 @@ class ConcreteMachine:
|
||||
bus_->apply_confidence(confidence_counter_);
|
||||
}
|
||||
|
||||
void flush_output(Output) final {
|
||||
void flush_output(int) final {
|
||||
bus_->flush();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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];
|
||||
|
Loading…
x
Reference in New Issue
Block a user