diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 5f6bd7682..cd2c4f620 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -72,23 +72,17 @@ class MachineDocument: self.configureAs(analyser) self.fileObserver = CSFileContentChangeObserver.init(url: url, handler: { DispatchQueue.main.async { -// self.actionLock.lock() -// self.drawLock.lock() - switch(self.machine.effectForFile(atURLDidChange: url)) { case .reinsertMedia: self.insertFile(url) case .restartMachine: let target = CSStaticAnalyser(fileAt: url) if let target = target { -// self.configureAs(target) + self.machine.substitute(target) } case .none: fallthrough @unknown default: break } - -// self.actionLock.unlock() -// self.drawLock.unlock() } }) } else { diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h index c2923804e..f78a33a83 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.h @@ -79,6 +79,8 @@ typedef NS_ENUM(NSInteger, CSMachineChangeEffect) { - (void)setMouseButton:(int)button isPressed:(BOOL)isPressed; - (void)addMouseMotionX:(CGFloat)deltaX y:(CGFloat)deltaY; +- (void)substitute:(nonnull CSStaticAnalyser *)machine; + @property (nonatomic, strong, nullable) CSAudioQueue *audioQueue; @property (nonatomic, readonly, nonnull) CSScanTargetView *view; @property (nonatomic, weak, nullable) id delegate; diff --git a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm index 355278a99..ffb1a8162 100644 --- a/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Machine/CSMachine.mm @@ -34,6 +34,7 @@ #include #include #include +#include namespace { @@ -50,6 +51,8 @@ struct MachineUpdater { MachineTypes::TimedMachine *timed_machine = nullptr; }; +using Updater = Concurrency::AsyncTaskQueue; + } @interface CSMachine() @@ -123,7 +126,7 @@ struct ActivityObserver: public Activity::Observer { CSJoystickManager *_joystickManager; NSMutableArray *_leds; - Concurrency::AsyncTaskQueue updater; + std::unique_ptr updater; Time::ScanSynchroniser _scanSynchroniser; NSTimer *_joystickTimer; @@ -161,9 +164,11 @@ struct ActivityObserver: public Activity::Observer { } return nil; } - updater.performer.machine = _machine.get(); - if(updater.performer.machine) { - updater.start(); + + updater = std::make_unique(); + updater->performer.machine = _machine.get(); + if(updater->performer.machine) { + updater->start(); } // Use the keyboard as a joystick if the machine has no keyboard, or if it has a 'non-exclusive' keyboard. @@ -191,6 +196,32 @@ struct ActivityObserver: public Activity::Observer { return self; } +- (void)substitute:(nonnull CSStaticAnalyser *)machine { + [self stop]; + + Machine::Error error; + ROM::Request missing_roms; + _machine = Machine::MachineForTargets(_analyser.targets, CSROMFetcher(&missing_roms), error); + + _view.scanTarget.scanTarget->will_change_owner(); + _machine->scan_producer()->set_scan_target(_view.scanTarget.scanTarget); + + updater = std::make_unique(); + updater->performer.machine = _machine.get(); + if(updater->performer.machine) { + updater->start(); + } + + Activity::Source *const activity_source = _machine->activity_source(); + if(activity_source) { + _activityObserver.machine = self; + activity_source->set_activity_observer(&_activityObserver); + } + + _speakerDelegate.machine = self; + [self.delegate machineSpeakerDidChangeInputClock:self]; +} + - (void)speaker:(Outputs::Speaker::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length { assert(NSUInteger(length) == self.audioQueue.bufferSize*(speaker->get_is_stereo() ? 2 : 1)); [self.audioQueue enqueueAudioBuffer:samples]; @@ -511,7 +542,7 @@ struct ActivityObserver: public Activity::Observer { } - (void)applyInputEvent:(dispatch_block_t)event { - updater.enqueue([event] { + updater->enqueue([event] { event(); }); } @@ -727,10 +758,10 @@ struct ActivityObserver: public Activity::Observer { - (void)audioQueueIsRunningDry:(nonnull CSAudioQueue *)audioQueue { __weak CSMachine *weakSelf = self; - updater.enqueue([weakSelf] { + updater->enqueue([weakSelf] { CSMachine *const strongSelf = weakSelf; if(strongSelf) { - strongSelf->updater.performer.timed_machine->flush_output(MachineTypes::TimedMachine::Output::Audio); + strongSelf->updater->performer.timed_machine->flush_output(MachineTypes::TimedMachine::Output::Audio); } }); } @@ -738,7 +769,7 @@ struct ActivityObserver: public Activity::Observer { - (void)scanTargetViewDisplayLinkDidFire:(CSScanTargetView *)view now:(const CVTimeStamp *)now outputTime:(const CVTimeStamp *)outputTime { __weak CSMachine *weakSelf = self; - updater.enqueue([weakSelf] { + updater->enqueue([weakSelf] { CSMachine *const strongSelf = weakSelf; if(!strongSelf) { return; @@ -746,7 +777,7 @@ struct ActivityObserver: public Activity::Observer { // Grab a pointer to the timed machine from somewhere where it has already // been dynamically cast, to avoid that cost here. - MachineTypes::TimedMachine *const timed_machine = strongSelf->updater.performer.timed_machine; + MachineTypes::TimedMachine *const timed_machine = strongSelf->updater->performer.timed_machine; // Definitely update video; update audio too if that pipeline is looking a little dry. auto outputs = MachineTypes::TimedMachine::Output::Video; @@ -785,7 +816,7 @@ struct ActivityObserver: public Activity::Observer { } - (void)stop { - updater.stop(); + updater->stop(); } + (BOOL)attemptInstallROM:(NSURL *)url {