From a2462b170a3c9466bd84f1a7db8aef76d4b6044e Mon Sep 17 00:00:00 2001 From: Will Cobb Date: Sun, 8 May 2016 12:20:31 -0500 Subject: [PATCH] Now correctly detects mute button --- desmume/src/gfx3d.cpp | 2 +- iNDS.xcodeproj/project.pbxproj | 18 ++- iNDS/AppDelegate.h | 2 +- iNDS/AppDelegate.m | 12 +- iNDS/SharkfoodMuteSwitchDetector.h | 21 ++++ iNDS/SharkfoodMuteSwitchDetector.m | 154 +++++++++++++++++++++++++ iNDS/core/emu.cpp | 56 ++------- iNDS/core/emu.h | 2 +- iNDS/iNDSEmulatorViewController.mm | 25 ++-- iNDS/iNDSSettingsTableViewController.m | 0 iNDS/mute.caf | Bin 0 -> 7298 bytes iNDS/roms/iNDSROMTableViewController.m | 2 + 12 files changed, 222 insertions(+), 72 deletions(-) create mode 100644 iNDS/SharkfoodMuteSwitchDetector.h create mode 100644 iNDS/SharkfoodMuteSwitchDetector.m mode change 100755 => 100644 iNDS/iNDSSettingsTableViewController.m create mode 100644 iNDS/mute.caf diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index e077884..1cc5d6d 100755 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -2180,7 +2180,7 @@ void gfx3d_execute3D() for(i=0;i + + +typedef void(^SharkfoodMuteSwitchDetectorBlock)(BOOL silent); + +@interface SharkfoodMuteSwitchDetector : NSObject + ++(SharkfoodMuteSwitchDetector*)shared; + +@property (nonatomic,readonly) BOOL isMute; +@property (nonatomic,copy) SharkfoodMuteSwitchDetectorBlock silentNotify; +@property (nonatomic) BOOL disabled; + +@end diff --git a/iNDS/SharkfoodMuteSwitchDetector.m b/iNDS/SharkfoodMuteSwitchDetector.m new file mode 100644 index 0000000..ea7ea2d --- /dev/null +++ b/iNDS/SharkfoodMuteSwitchDetector.m @@ -0,0 +1,154 @@ +// +// SharkfoodMuteSwitchDetector.m +// +// Created by Moshe Gottlieb on 6/2/13. +// Copyright (c) 2013 Sharkfood. All rights reserved. +// + +#import "SharkfoodMuteSwitchDetector.h" +#import + +/** + Sound completion proc - this is the real magic, we simply calculate how long it took for the sound to finish playing + In silent mode, playback will end very fast (but not in zero time) + */ +void SharkfoodSoundMuteNotificationCompletionProc(SystemSoundID ssID,void* clientData); + +@interface SharkfoodMuteSwitchDetector() +/** + Find out how fast the completion call is called + */ +@property (nonatomic,assign) NSTimeInterval interval; +/** + Our silent sound (0.5 sec) + */ +@property (nonatomic,assign) SystemSoundID soundId; +/** + Set to true after the block was set or during init. + Otherwise the block is called only when the switch value actually changes + */ +@property (nonatomic,assign) BOOL forceEmit; +/** + Sound completion, objc + */ +-(void)complete; +/** + Our loop, checks sound switch + */ +-(void)loopCheck; +/** + Pause while in the background, if your app supports playing audio in the background, you want this. + Otherwise your app will be rejected. + */ +-(void)didEnterBackground; +/** + Resume when entering foreground + */ +-(void)willReturnToForeground; +/** + Schedule a next check + */ +-(void)scheduleCall; +/** + Is paused? + */ +@property (nonatomic,assign) BOOL isPaused; +/** + Currently playing? used when returning from the background (if went to background and foreground really quickly) +*/ +@property (nonatomic,assign) BOOL isPlaying; + +@end + + + +void SharkfoodSoundMuteNotificationCompletionProc(SystemSoundID ssID,void* clientData){ + SharkfoodMuteSwitchDetector* detecotr = (__bridge SharkfoodMuteSwitchDetector*)clientData; + [detecotr complete]; +} + + +@implementation SharkfoodMuteSwitchDetector + +-(id)init{ + self = [super init]; + if (self){ + NSURL* url = [[NSBundle mainBundle] URLForResource:@"mute" withExtension:@"caf"]; + if (AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &_soundId) == kAudioServicesNoError){ + AudioServicesAddSystemSoundCompletion(self.soundId, CFRunLoopGetMain(), kCFRunLoopDefaultMode, SharkfoodSoundMuteNotificationCompletionProc,(__bridge void *)(self)); + UInt32 yes = 1; + AudioServicesSetProperty(kAudioServicesPropertyIsUISound, sizeof(_soundId),&_soundId,sizeof(yes), &yes); + [self performSelector:@selector(loopCheck) withObject:nil afterDelay:1]; + self.forceEmit = YES; + } else { + NSLog(@"Sharkfood Error"); + self.soundId = -1; + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willReturnToForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; + } + return self; +} + +-(void)didEnterBackground{ + self.isPaused = YES; +} +-(void)willReturnToForeground{ + self.isPaused = NO; + if (!self.isPlaying){ + [self scheduleCall]; + } +} + +-(void)setSilentNotify:(SharkfoodMuteSwitchDetectorBlock)silentNotify{ + _silentNotify = [silentNotify copy]; + self.forceEmit = YES; +} + ++(SharkfoodMuteSwitchDetector*)shared{ + static SharkfoodMuteSwitchDetector* sShared = nil; + if (!sShared) + sShared = [SharkfoodMuteSwitchDetector new]; + return sShared; +} + +-(void)scheduleCall{ + [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(loopCheck) object:nil]; + [self performSelector:@selector(loopCheck) withObject:nil afterDelay:1]; +} + + + +-(void)complete{ + self.isPlaying = NO; + NSTimeInterval elapsed = [NSDate timeIntervalSinceReferenceDate] - self.interval; + BOOL isMute = elapsed < 0.1; // Should have been 0.5 sec, but it seems to return much faster (0.3something) + if (self.isMute != isMute || self.forceEmit) { + self.forceEmit = NO; + _isMute = isMute; + if (self.silentNotify) + self.silentNotify(isMute); + } + [self scheduleCall]; +} + +-(void)loopCheck{ + if (!self.isPaused){ + self.interval = [NSDate timeIntervalSinceReferenceDate]; + self.isPlaying = YES; + AudioServicesPlaySystemSound(self.soundId); + } +} + + +// For reference only, this DTOR will never be invoked. + +-(void)dealloc{ + if (self.soundId != -1){ + AudioServicesRemoveSystemSoundCompletion(self.soundId); + AudioServicesDisposeSystemSoundID(self.soundId); + } + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end diff --git a/iNDS/core/emu.cpp b/iNDS/core/emu.cpp index e9bf4d8..8462410 100755 --- a/iNDS/core/emu.cpp +++ b/iNDS/core/emu.cpp @@ -353,53 +353,21 @@ void iNDS_user() mainLoopData.fpsframecount = 0; mainLoopData.fpsticks = GetTickCount(); } - - //Don't think this does very much - return; - if(nds.idleFrameCounter==0 || oneSecond) - { - //calculate a 16 frame arm9 load average - for(int cpu=0;cpu<2;cpu++) - { - int load = 0; - //printf("%d: ",cpu); - for(int i=0;i<16;i++) - { - //blend together a few frames to keep low-framerate games from having a jittering load average - //(they will tend to work 100% for a frame and then sleep for a while) - //4 frames should handle even the slowest of games - s32 sample = - nds.runCycleCollector[cpu][(i+0+nds.idleFrameCounter)&15] - + nds.runCycleCollector[cpu][(i+1+nds.idleFrameCounter)&15] - + nds.runCycleCollector[cpu][(i+2+nds.idleFrameCounter)&15] - + nds.runCycleCollector[cpu][(i+3+nds.idleFrameCounter)&15]; - sample /= 4; - load = load/8 + sample*7/8; - } - //printf("\n"); - load = std::min(100,std::max(0,(int)(load*100/1120380))); - //Hud.cpuload[cpu] = load; - } - } - - //Hud.cpuloopIterationCount = nds.cpuloopIterationCount; } -void iNDS_throttle(bool allowSleep, int forceFrameSkip) +void iNDS_throttle() { - int skipRate = (forceFrameSkip < 0) ? frameskiprate : forceFrameSkip; - int ffSkipRate = (forceFrameSkip < 0) ? 9 : forceFrameSkip; //Change in skip rate - if(lastskiprate != skipRate) + if(lastskiprate != frameskiprate) { - lastskiprate = skipRate; + lastskiprate = frameskiprate; mainLoopData.framestoskip = 0; // otherwise switches to lower frameskip rates will lag behind } //Load a frame - if(!mainLoopData.skipnextframe || forceFrameSkip == 0 || frameAdvance || (continuousframeAdvancing && !FastForward)) + if(!mainLoopData.skipnextframe) { mainLoopData.framesskipped = 0; @@ -420,32 +388,22 @@ void iNDS_throttle(bool allowSleep, int forceFrameSkip) NDS_SkipNextFrame(); } - if ((/*autoframeskipenab && frameskiprate ||*/ FrameLimit) && allowSleep) - { - SpeedThrottle(); - } - if (autoframeskipenab && frameskiprate) { if(!frameAdvance && !continuousframeAdvancing) { AutoFrameSkip_NextFrame(); if (mainLoopData.framestoskip < 1) - mainLoopData.framestoskip += AutoFrameSkip_GetSkipAmount(0,skipRate); + mainLoopData.framestoskip += AutoFrameSkip_GetSkipAmount(0, frameskiprate); } } + else { if (mainLoopData.framestoskip < 1) - mainLoopData.framestoskip += skipRate; + mainLoopData.framestoskip += frameskiprate; } - if (frameAdvance && allowSleep) - { - frameAdvance = false; - emu_halt(); - SPU_Pause(1); - } if(execute && emu_paused && !frameAdvance) { // safety net against running out of control in case this ever happens. diff --git a/iNDS/core/emu.h b/iNDS/core/emu.h index befe2d7..153a3a4 100755 --- a/iNDS/core/emu.h +++ b/iNDS/core/emu.h @@ -38,7 +38,7 @@ bool EMU_loadRom(const char* path); void EMU_change3D(int type); void EMU_changeSound(int type); void EMU_enableSound(bool enable); -void iNDS_throttle(bool allowSleep = true, int forceFrameSkip = -1); +void iNDS_throttle(); void EMU_setFrameSkip(int skip); void EMU_setCPUMode(int cpuMode); void EMU_setSynchMode(bool enabled); diff --git a/iNDS/iNDSEmulatorViewController.mm b/iNDS/iNDSEmulatorViewController.mm index 620b552..358da32 100644 --- a/iNDS/iNDSEmulatorViewController.mm +++ b/iNDS/iNDSEmulatorViewController.mm @@ -14,8 +14,10 @@ #import "iNDSDirectionalControl.h" #import "iNDSButtonControl.h" #import "CHBgDropboxSync.h" + #import "UIDevice+Private.h" #import "RBVolumeButtons.h" +#import "SharkfoodMuteSwitchDetector.h" #import #import @@ -132,6 +134,7 @@ @interface iNDSEmulatorViewController () { UINavigationController * settingsNav; RBVolumeButtons *volumeStealer; + SharkfoodMuteSwitchDetector *muteDetector; dispatch_semaphore_t displaySemaphore; } @@ -226,6 +229,12 @@ - (void)viewDidLoad }); }; + muteDetector = [SharkfoodMuteSwitchDetector shared]; + __weak iNDSEmulatorViewController* weakself = self; + muteDetector.silentNotify = ^(BOOL silent){ + [weakself defaultsChanged:nil]; + }; + [self defaultsChanged:nil]; @@ -325,13 +334,12 @@ - (void)defaultsChanged:(NSNotification*)notification NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; if (emuLoopLock) { //Only update these is the core has loaded EMU_setFrameSkip((int)[defaults integerForKey:@"frameSkip"]); - EMU_enableSound(![defaults boolForKey:@"disableSound"]); EMU_setSynchMode([defaults boolForKey:@"synchSound"]); - // Enable sound? + // (Mute on && don't ignore it) or user has sound disabled - BOOL muteSound = ([self muteButtonOn] && ![defaults boolForKey:@"ignoreMute"]) || [defaults boolForKey:@"disableSound"]; + BOOL muteSound = (muteDetector.isMute && ![defaults boolForKey:@"ignoreMute"]) || [defaults boolForKey:@"disableSound"]; EMU_enableSound(!muteSound); - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:(AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDefaultToSpeaker) @@ -355,11 +363,6 @@ - (void)defaultsChanged:(NSNotification*)notification [self.view setNeedsLayout]; } -// Not sure if we can figure this out -- (BOOL)muteButtonOn -{ - return NO; -} -(BOOL) isPortrait { @@ -720,7 +723,6 @@ - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect - (void) setSpeed:(CGFloat)speed { if (!self.program) return; - int userFrameSkip = (int)[[NSUserDefaults standardUserDefaults] integerForKey:@"frameSkip"]; if (speed < 1) { //Force this. Audio sounds so bad < 1 when synched EMU_setSynchMode(0); } else { @@ -924,6 +926,7 @@ - (IBAction)toggleSettings:(id)sender //}); } else { + if ([[NSUserDefaults standardUserDefaults] integerForKey:@"volumeBumper"]) { [volumeStealer performSelector:@selector(startStealingVolumeButtonEvents) withObject:nil afterDelay:0.1]; } @@ -938,7 +941,7 @@ - (IBAction)toggleSettings:(id)sender [self resumeEmulation]; self.darkenView.hidden = YES; }]; - + disableTouchScreen = [[NSUserDefaults standardUserDefaults] boolForKey:@"disableTouchScreen"]; [self setLidClosed:NO]; diff --git a/iNDS/iNDSSettingsTableViewController.m b/iNDS/iNDSSettingsTableViewController.m old mode 100755 new mode 100644 diff --git a/iNDS/mute.caf b/iNDS/mute.caf new file mode 100644 index 0000000000000000000000000000000000000000..d0df847a06e6bcf7478549c9873a7219bf74448c GIT binary patch literal 7298 zcmeHLL2er{43zC8y%cDl(5K`pMq-~@plJJozNkOwyV}IraAr87cH`cA&;skFv=lir zq_jvLj^}gRwf1=W{?K%Ny8nGo>+{!#FFCi5XL#}cc>Z=eY5v2nd_NykfvLb$U@9;b zm1?T-wK6lGY+w)#pTb8gd?GWSmYd=Oi&UggB zMsK~vc(B43Z=c(3+nt=S!kM9@s*&OO%yU)_QGlBLd-0>@lM_R3S&k0A=MZoxvooL<)Ap#d+a| z4#1z4N#4>SR0+>OqAQ~TnYeY{crQ=<#*J!~zM6Z(Frz5TR-XZT=FOhySP;*3=onW$ z09J~Vb?wNu)ps=%ygC>2<84%0?^RoWGp$N&H0~U#@6f3psTZvzqTeh}$ptzMyC~~5 zVl=9eiz8M)86%&Jq8)a({EckU_f*$?0Q^tfeU*D#4=Yu*0D|0|5$zBW-YtJ3$|ZWr znt{)4yg^Q(>lnGFDu)%$F1{SGrnORU1`OmuO=w98^)J@1PaW4+J=qy$3~18P*~$u7 zsfr*ZJ%*LovgEvwR83TI>4M0(t&`LF{dO`ey1Hw#B1CLd{x*zRqk*HaxWb#QX5 zQMnuN4J~|w6s~bhnXe)UEl>J%2YQUx?9oNYN+r8h)f&4DK6sNFleN~B9vp|?+o$)g z_C%c<@(k2@ngNY8m)eodgyW60B`Rj|j;lId>CW)f`CGdjR>c*s7{@FaUbm=IFjKG8 zS?KBkrqKh1ZGCmtn%Hw)5AWUh{*f~xM5GughH9&sD>cHJWZ;uSUheL`p3(pD!)(B% zFV>jHw)DYo_Am4HnsbEcQb2LS8&^b6D@TqA#L8J!GG0_fTG$c-udR_S^iJKXhITqC z96O!Zkx!OAQt^&lI~TKLX9i#)CTolQ#6;g+=fOFq^Tj-nQF^#P*y%B=+PTZ*)0y%; zbjfI4YXrkZtck;&oQiX;Rj4yln$agba?~wEtll*?eEEQB`%bJd>*|}eVj!!(i2WoP H;>XHYmp>+x literal 0 HcmV?d00001 diff --git a/iNDS/roms/iNDSROMTableViewController.m b/iNDS/roms/iNDSROMTableViewController.m index 971e4ee..ebcde48 100644 --- a/iNDS/roms/iNDSROMTableViewController.m +++ b/iNDS/roms/iNDSROMTableViewController.m @@ -16,6 +16,7 @@ #import "MHWDirectoryWatcher.h" #import "WCEasySettingsViewController.h" #import "WCBuildStoreClient.h" +#import "SharkfoodMuteSwitchDetector.h" @interface iNDSROMTableViewController () { NSMutableArray * activeDownloads; @@ -43,6 +44,7 @@ - (void)viewDidLoad }); } #endif + [SharkfoodMuteSwitchDetector shared]; //Start detecting } - (void)didReceiveMemoryWarning