Open ghostforest opened 5 months ago
Thanks and interesting. I will have a look into it.
Im trying to add Swinsian support but I'm having issues getting it done. I used the Doppler.h and repurposed everything to Swinsian, changed the ApplicationIDHandle in AppDelegate, but no luck so far. Swinsian has a scriptable variable called sound volume, same as iTunes.
-- Reply to this email directly or view it on GitHub: https://github.com/alberti42/Volume-Control/issues/25 You are receiving this because you are subscribed to this thread.
Message ID: @.***>
I figured a bit more out:
Volume Control recognizes swinisian because an error occurs when I actually want to change volume but this only happens if swinisian is actually playing a track. So I guess volume control finds Swinsian at the correct "com.swinsian.Swinsian" handle.
This is the code for swinisian.h /*
@class SwinsianTrack, SwinsianApplication;
enum SwinsianEPlS { SwinsianEPlSStopped = 'kPSS', SwinsianEPlSPlaying = 'kPSP', SwinsianEPlSPaused = 'kPSp' }; typedef enum SwinsianEPlS SwinsianEPlS;
/*
// playable track @interface SwinsianTrack : SBObject
(NSString ) id; // the id of the track @property (copy, readonly) NSString name; // the title of the track @property (copy, readonly) NSImage artwork; // a piece of art within a track @property (copy, readonly) NSString album; // the album name of the track @property (copy, readonly) NSString albumArtist; // the album artist of the track @property (copy, readonly) NSString artist; // the artist of the track @property BOOL loved; // is this track loved?
(void) reveal; // reveal and select the specified track
@end
// The application program @interface DopplerApplication : SBApplication
@property (copy, readonly) SwinsianTrack *currentTrack; // the currently playing track @property (readonly) SwinsianEPlS playerState; // the current state of the audio player @property BOOL shuffleEnabled; // are songs played in random order? @property NSInteger soundVolume; // the sound output volume (0 = minimum, 100 = maximum)
@end
And here is the code for the appdelegate: // // AppDelegate.m // iTunes Volume Control // // Created by Andrea Alberti on 25.12.12. // Copyright (c) 2012 Andrea Alberti. All rights reserved. //
//This will handle signals for us, specifically SIGTERM. void handleSIGTERM(int sig) { [NSApp terminate:nil]; }
//static void displayPreferencesChanged(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void *userInfo) { // [[NSNotificationCenter defaultCenter] postNotificationName:@"displayResolutionHasChanged" object:NULL]; //}
CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void refcon) { static int previousKeyCode = 0; static bool muteDown = false; NSEvent sysEvent;
if (type == kCGEventTapDisabledByTimeout) {
// NSLog(@"Event Taps Disabled! Re-enabling");
[(__bridge AppDelegate *)(refcon) resetEventTap];
return event;
}
// No event we care for, then return ASAP
if (type != NX_SYSDEFINED) return event;
sysEvent = [NSEvent eventWithCGEvent:event];
// No need to test event type, we know it is NSSystemDefined, becuase that is the same as NX_SYSDEFINED
// if ([sysEvent subtype] != NX_SUBTYPE_AUX_CONTROL_BUTTONS && [sysEvent subtype] != NX_SUBTYPE_AUX_MOUSE_BUTTONS) return event;
if ([sysEvent subtype] != NX_SUBTYPE_AUX_CONTROL_BUTTONS) return event;
AppDelegate* app=(__bridge AppDelegate *)(refcon);
int keyFlags = ([sysEvent data1] & 0x0000FFFF);
int keyCode = (([sysEvent data1] & 0xFFFF0000) >> 16);
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
bool keyIsRepeat = (keyFlags & 0x1);
CGEventFlags keyModifier = [sysEvent modifierFlags]|0xFFFF;
// store whether Apple CMD modifier has been pressed or not
[app setAppleCMDModifierPressed:(keyModifier&NX_COMMANDMASK)==NX_COMMANDMASK];
switch( keyCode )
{
case NX_KEYTYPE_MUTE:
if(previousKeyCode!=keyCode && app->volumeRampTimer)
{
[app stopVolumeRampTimer];
}
previousKeyCode=keyCode;
if( keyState == 1 )
{
muteDown = true;
[[NSNotificationCenter defaultCenter] postNotificationName:@"MuteVol" object:NULL];
}
else
{
muteDown = false;
}
return NULL;
break;
case NX_KEYTYPE_SOUND_UP:
case NX_KEYTYPE_SOUND_DOWN:
if(!muteDown)
{
if(previousKeyCode!=keyCode && app->volumeRampTimer)
{
[app stopVolumeRampTimer];
}
previousKeyCode=keyCode;
if( keyState == 1 )
{
if( !app->volumeRampTimer )
{
if( keyCode == NX_KEYTYPE_SOUND_UP )
[[NSNotificationCenter defaultCenter] postNotificationName:(keyIsRepeat?@"IncVolRamp":@"IncVol") object:NULL];
else
[[NSNotificationCenter defaultCenter] postNotificationName:(keyIsRepeat?@"DecVolRamp":@"DecVol") object:NULL];
}
}
else
{
if(app->volumeRampTimer)
{
[app stopVolumeRampTimer];
}
}
return NULL;
}
break;
}
return event;
}
@interface AppDelegate ()
NSView* _hintView;
NSViewController* _hintVC;
}
@end
@implementation PlayerApplication
@synthesize currentVolume = _currentVolume;
(void) setCurrentVolume:(double)currentVolume { [self setDoubleVolume:currentVolume];
[musicPlayer setSoundVolume:round(currentVolume)]; }
(double) currentVolume { double vol = [musicPlayer soundVolume];
if (fabs(vol-[self doubleVolume])<1) { vol = [self doubleVolume]; }
return vol; }
(void) nextTrack { return [musicPlayer nextTrack]; }
(void) previousTrack { return [musicPlayer previousTrack]; }
(void) playPause { return [musicPlayer playPause]; }
(BOOL) isRunning { return [musicPlayer isRunning]; }
(iTunesEPlS) playerState { return [musicPlayer playerState]; }
-(id)initWithBundleIdentifier:(NSString*) bundleIdentifier { if (self = [super init]) { [self setCurrentVolume: -100]; [self setOldVolume: -1]; musicPlayer = [SBApplication applicationWithBundleIdentifier:bundleIdentifier];
}
return self;
}
@end
@implementation AppDelegate
// @synthesize AppleRemoteConnected=_AppleRemoteConnected; @synthesize StartAtLogin=_StartAtLogin; @synthesize Tapping=_Tapping; @synthesize UseAppleCMDModifier=_UseAppleCMDModifier; @synthesize AppleCMDModifierPressed=_AppleCMDModifierPressed; @synthesize AutomaticUpdates=_AutomaticUpdates; @synthesize hideFromStatusBar = _hideFromStatusBar; @synthesize hideVolumeWindow = _hideVolumeWindow; @synthesize loadIntroAtStart = _loadIntroAtStart; @synthesize statusBar = _statusBar;
@synthesize iTunesBtn = _iTunesBtn; @synthesize spotifyBtn = _spotifyBtn; @synthesize systemBtn = _systemBtn; @synthesize swinsianBtn = _swinsianBtn;
@synthesize iTunesPerc = _iTunesPerc; @synthesize spotifyPerc = _spotifyPerc; @synthesize systemPerc = _systemPerc; @synthesize swinsianPerc = _swinsianPerc;
@synthesize sparkle_updater = _sparkle_updater;
@synthesize statusMenu = _statusMenu;
static NSTimeInterval volumeRampTimeInterval=0.01f; static NSTimeInterval statusBarHideDelay=10.0f; static NSTimeInterval checkPlayerTimeout=0.3f; static NSTimeInterval updateSystemVolumeInterval=0.1f;
(IBAction)terminate:(id)sender { if(CFMachPortIsValid(eventTap)) { CFMachPortInvalidate(eventTap); CFRunLoopSourceInvalidate(runLoopSource); CFRelease(eventTap); CFRelease(runLoopSource); }
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
systemAudio = nil; iTunes = nil; spotify = nil; swinsian = nil;
_statusBar = nil;
accessibilityDialog = nil; introWindowController = nil;
[volumeRampTimer invalidate]; volumeRampTimer = nil;
[checkPlayerTimer invalidate]; checkPlayerTimer = nil;
[timerImgSpeaker invalidate]; timerImgSpeaker = nil;
[updateSystemVolumeTimer invalidate]; updateSystemVolumeTimer = nil;
preferences = nil;
[NSApp terminate:nil]; }
(bool) StartAtLogin { NSURL *appURL=[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
bool found=false;
if (loginItems) { UInt32 seedValue; //Retrieve the list of Login Items and cast them to a NSArray so that it will be easier to iterate. NSArray loginItemsArray = (__bridge NSArray )LSSharedFileListCopySnapshot(loginItems, &seedValue);
for(int i=0; i<[loginItemsArray count]; i++)
{
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i];
//Resolve the item with URL
CFURLRef url = NULL;
// LSSharedFileListItemResolve is deprecated in Mac OS X 10.10
// Switch to LSSharedFileListItemCopyResolvedURL if possible
LSSharedFileListItemResolve(itemRef, 0, &url, NULL);
url = LSSharedFileListItemCopyResolvedURL(itemRef, 0, NULL);
if ( url ) {
if ( CFEqual(url, (__bridge CFTypeRef)(appURL)) ) // found it
{
found=true;
}
CFRelease(url);
}
if(found)break;
}
CFRelease((__bridge CFTypeRef)(loginItemsArray));
CFRelease(loginItems);
}
return found; }
(void)wasAuthorized { [accessibilityDialog close]; accessibilityDialog = nil;
[self completeInitialization]; }
(void)setStartAtLogin:(bool)enabled savePreferences:(bool)savePreferences { NSMenuItem* menuItem=[_statusMenu itemWithTag:4]; [menuItem setState:enabled];
if(savePreferences) { NSURL *appURL=[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginItems) {
if(enabled)
{
// Insert the item at the bottom of Login Items list.
LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginItems,
kLSSharedFileListItemLast,
NULL,
NULL,
(__bridge CFURLRef)appURL,
NULL,
NULL);
if (loginItemRef) {
CFRelease(loginItemRef);
}
}
else
{
UInt32 seedValue;
//Retrieve the list of Login Items and cast them to a NSArray so that it will be easier to iterate.
NSArray *loginItemsArray = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue);
for(int i=0; i<[loginItemsArray count]; i++)
{
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)[loginItemsArray objectAtIndex:i];
//Resolve the item with URL
CFURLRef URL = NULL;
// LSSharedFileListItemResolve is deprecated in Mac OS X 10.10
// Switch to LSSharedFileListItemCopyResolvedURL if possible
LSSharedFileListItemResolve(itemRef, 0, &URL, NULL);
URL = LSSharedFileListItemCopyResolvedURL(itemRef, 0, NULL);
if ( URL ) {
if ( CFEqual(URL, (__bridge CFTypeRef)(appURL)) ) // found it
{
LSSharedFileListItemRemove(loginItems,itemRef);
}
CFRelease(URL);
}
}
CFRelease((__bridge CFTypeRef)(loginItemsArray));
}
CFRelease(loginItems);
}
} }
(void)stopVolumeRampTimer { [volumeRampTimer invalidate]; volumeRampTimer=nil; [[NSNotificationCenter defaultCenter] postNotificationName:@"SoundFeedback" object:NULL];
checkPlayerTimer = [NSTimer timerWithTimeInterval:checkPlayerTimeout target:self selector:@selector(resetCurrentPlayer:) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:checkPlayerTimer forMode:NSRunLoopCommonModes]; }
(void)rampVolumeUp:(NSTimer*)theTimer { [self setVolumeUp:true]; }
(void)rampVolumeDown:(NSTimer*)theTimer { [self setVolumeUp:false]; }
(bool)createEventTap { if(eventTap != nil && CFMachPortIsValid(eventTap)) { CFMachPortInvalidate(eventTap); CFRunLoopSourceInvalidate(runLoopSource); CFRelease(eventTap); CFRelease(runLoopSource); }
CGEventMask eventMask = (/(1 << kCGEventKeyDown) | (1 << kCGEventKeyUp) |/CGEventMaskBit(NX_SYSDEFINED)); eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, eventMask, event_tap_callback, (__bridge void *)self); // Create an event tap. We are interested in SYS key presses.
if(eventTap != nil) { runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0); // Create a run loop source. CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); // Add to the current run loop. return true; } else return false; }
-(void) sendMediaKey: (int)key { // create and send down key event NSEvent* key_event;
key_event = [NSEvent otherEventWithType:NSEventTypeSystemDefined location:CGPointZero modifierFlags:0xa00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:((key << 16) | (0xa << 8)) data2:-1];
CGEventPost(0, key_event.CGEvent);
// NSLog(@"%d keycode (down) sent",key);
// create and send up key event
key_event = [NSEvent otherEventWithType:NSEventTypeSystemDefined location:CGPointZero modifierFlags:0xb00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:((key << 16) | (0xb << 8)) data2:-1];
CGEventPost(0, key_event.CGEvent);
// NSLog(@"%d keycode (up) sent",key);
}
(void)PlayPauseMusic:(NSNotification *)aNotification { [self sendMediaKey:NX_KEYTYPE_PLAY]; }
(void)NextTrackMusic:(NSNotification *)aNotification { [self sendMediaKey:NX_KEYTYPE_NEXT]; }
(void)PreviousTrackMusic:(NSNotification *)aNotification { [self sendMediaKey:NX_KEYTYPE_PREVIOUS]; }
(void)MuteVol:(NSNotification *)aNotification { id musicPlayerPnt = [self runningPlayer];
if (musicPlayerPnt != nil) { if([musicPlayerPnt oldVolume]<0) { [musicPlayerPnt setOldVolume:[musicPlayerPnt currentVolume]]; [musicPlayerPnt setCurrentVolume:0];
if(!_hideVolumeWindow)
[[self->OSDManager sharedManager] showImage:OSDGraphicSpeakerMute onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:0 totalChiclets:(unsigned int)100 locked:NO];
}
else
{
[musicPlayerPnt setCurrentVolume:[musicPlayerPnt oldVolume]];
[volumeImageLayer setContents:imgVolOn];
if(!_hideVolumeWindow)
[[self->OSDManager sharedManager] showImage:OSDGraphicSpeaker onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)[musicPlayerPnt oldVolume] totalChiclets:(unsigned int)100 locked:NO];
[musicPlayerPnt setOldVolume:-1];
}
if (musicPlayerPnt == iTunes)
[self setItunesVolume:[musicPlayerPnt currentVolume]];
else if (musicPlayerPnt == spotify)
[self setSpotifyVolume:[musicPlayerPnt currentVolume]];
else if (musicPlayerPnt == swinsian)
[self setSwinsianVolume:[musicPlayerPnt currentVolume]];
else if (musicPlayerPnt == systemAudio)
[self setSystemVolume:[musicPlayerPnt currentVolume]];
} }
(void)IncVol:(NSNotification )aNotification { if( [[aNotification name] isEqualToString:@"IncVolRamp"] ) { [checkPlayerTimer invalidate]; checkPlayerTimer = nil; volumeRampTimer=[NSTimer timerWithTimeInterval:volumeRampTimeInterval(NSTimeInterval)increment target:self selector:@selector(rampVolumeUp:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:volumeRampTimer forMode:NSRunLoopCommonModes];
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
} else { [self setVolumeUp:true]; } }
(void)DecVol:(NSNotification )aNotification { if( [[aNotification name] isEqualToString:@"DecVolRamp"] ) { [checkPlayerTimer invalidate]; checkPlayerTimer = nil; volumeRampTimer=[NSTimer timerWithTimeInterval:volumeRampTimeInterval(NSTimeInterval)increment target:self selector:@selector(rampVolumeDown:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:volumeRampTimer forMode:NSRunLoopCommonModes];
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
} else { [self setVolumeUp:false]; } }
(id)init { self = [super init]; if(self) { self->eventTap = nil;
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_6) {
//10.6.x or earlier systems
osxVersion = 106;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_7) {
/* On a 10.7 - 10.7.x system */
osxVersion = 107;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_8) {
/* On a 10.8 - 10.8.x system */
osxVersion = 108;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9) {
/* On a 10.9 - 10.9.x system */
osxVersion = 109;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_10) {
/* On a 10.10 - 10.10.x system */
osxVersion = 110;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_11) {
/* On a 10.11 - 10.11.x system */
osxVersion = 111;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_12) {
/* On a 10.12 - 10.12.x system */
osxVersion = 112;
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_13) {
/* On a 10.13 - 10.13.x system */
osxVersion = 113;
} else if (floor(NSAppKitVersionNumber) <= 1671) {
/* On a 10.14 - 10.14.x system */
osxVersion = 114;
}
else if (floor(NSAppKitVersionNumber) <= 1894) {
/* On a 10.15 - 10.15.x system */
osxVersion = 115;
}
else
{
osxVersion = 115;
}
menuIsVisible=false;
currentPlayer=nil;
updateSystemVolumeTimer=nil;
volumeRampTimer=nil;
timerImgSpeaker=nil;
checkPlayerTimer=nil;
} return self; }
-(void)awakeFromNib { }
-(void)completeInitialization { NSDictionary infoDict = [[NSBundle mainBundle] infoDictionary]; //NSString version = [infoDict objectForKey:@"CFBundleShortVersionString"]; //NSString operatingSystemVersionString = [[NSProcessInfo processInfo] operatingSystemVersionString]; NSString releasesCast = [infoDict objectForKey:@"ReleasesCast"];
SPUUpdater* updater = [[self sparkle_updater] updater];
[updater setFeedURL:[NSURL URLWithString:releasesCast]];
[updater setUpdateCheckInterval:60*60*24*7]; // look for new updates every 7 days
//[[SUUpdater sharedUpdater] setFeedURL:[NSURL URLWithString:[NSString stringWithFormat: @"http://quantum-technologies.iap.uni-bonn.de/alberti/iTunesVolumeControl/VolumeControlCast.xml.php?version=%@&osxversion=%@",version,[operatingSystemVersionString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]]]];
//[[SUUpdater sharedUpdater] setUpdateCheckInterval:60*60*24*7]; // look for new updates every 7 days
// [self _loadBezelServices]; // El Capitan and probably older systems
[[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/OSD.framework"] load];
self->OSDManager = NSClassFromString(@"OSDManager");
//[self checkSIPforAppIdentifier:@"com.apple.iTunes" promptIfNeeded:YES];
//[self checkSIPforAppIdentifier:@"com.spotify.client" promptIfNeeded:YES];
if(osxVersion >= 115)
iTunes = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.apple.Music"];
else
iTunes = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.apple.iTunes"];
spotify = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.spotify.client"];
swinsian = [[PlayerApplication alloc] initWithBundleIdentifier:@"com.swinsian.Swinsian"]; //com.swinsian.Swinsian
// Force MacOS to ask for authorization to AppleEvents if this was not already given
if([iTunes isRunning])
[iTunes currentVolume];
if([spotify isRunning])
[spotify currentVolume];
if([swinsian isRunning])
[swinsian currentVolume];
systemAudio = [[SystemApplication alloc] initWithVersion:osxVersion];
[self showInStatusBar]; // Install icon into the menu bar
// NSString* iTunesVersion = [[NSString alloc] initWithString:[iTunes version]];
// NSString* spotifyVersion = [[NSString alloc] initWithString:[spotify version]];
[self initializePreferences];
[self setStartAtLogin:[self StartAtLogin] savePreferences:false];
volumeSound = [[NSSound alloc] initWithContentsOfFile:@"/System/Library/LoginPlugins/BezelServices.loginPlugin/Contents/Resources/volume.aiff" byReference:false];
}
(void)emitAcousticFeedback:(NSNotification *)aNotification { if([self PlaySoundFeedback] && (_AppleCMDModifierPressed != _UseAppleCMDModifier || [[self runningPlayer] isKindOfClass:[SystemApplication class]])) { if([volumeSound isPlaying]) [volumeSound stop]; [volumeSound play]; } }
(void)applicationDidFinishLaunching:(NSNotification *)aNotification { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitAcousticFeedback:) name:@"SoundFeedback" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IncVol:) name:@"IncVol" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IncVol:) name:@"IncVolRamp" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DecVol:) name:@"DecVol" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DecVol:) name:@"DecVolRamp" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(MuteVol:) name:@"MuteVol" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(PlayPauseMusic:) name:@"PlayPauseMusic" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(NextTrackMusic:) name:@"NextTrackMusic" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(PreviousTrackMusic:) name:@"PreviousTrackMusic" object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self selector: @selector(receiveWakeNote:) name:NSWorkspaceDidWakeNotification object: NULL];
signal(SIGTERM, handleSIGTERM);
extern CFStringRef kAXTrustedCheckOptionPrompt attribute((weak_import));
if( AXIsProcessTrustedWithOptions((bridge CFDictionaryRef)@{(bridge id)kAXTrustedCheckOptionPrompt: @NO}) && [self createEventTap] ) { [self completeInitialization]; } else { accessibilityDialog = [[AccessibilityDialog alloc] initWithWindowNibName:@"AccessibilityDialog"];
[accessibilityDialog showWindow:self];
} }
(BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag { [self showInStatusBar]; [self setHideFromStatusBar:[self hideFromStatusBar]]; if ([self hideFromStatusBar]) { [self showHideFromStatusBarHintPopover]; }
return false; }
(void)showInStatusBar { if (![self statusBar]) { // the status bar item needs a custom view so that we can show a NSPopover for the hide-from-status-bar hint // the view now reacts to the mouseDown event to show the menu
_statusBar = [[NSStatusBar systemStatusBar] statusItemWithLength:15];
[[self statusBar] setMenu:[self statusMenu]];
}
NSImage* icon = [NSImage imageNamed:@"statusbar-icon"]; [icon setTemplate:YES];
NSStatusBarButton *statusBarButton = [[self statusBar] button]; [statusBarButton setImage:icon]; [statusBarButton setAppearsDisabled:false];
}
(void)updateSystemVolume:(NSTimer*)theTimer { if([systemAudio isMuted]) [[self systemPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",0]]; else [[self systemPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)[systemAudio currentVolume]]]; }
(void)initializePreferences { preferences = [NSUserDefaults standardUserDefaults]; NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt:2], @"volumeIncrement", [NSNumber numberWithBool:true] , @"TappingEnabled", [NSNumber numberWithBool:false], @"UseAppleCMDModifier", [NSNumber numberWithBool:true], @"AutomaticUpdates", [NSNumber numberWithBool:false], @"hideFromStatusBarPreference", [NSNumber numberWithBool:false], @"hideVolumeWindowPreference", [NSNumber numberWithBool:true], @"iTunesControl", [NSNumber numberWithBool:true], @"spotifyControl", [NSNumber numberWithBool:true], @"swinsianControl", [NSNumber numberWithBool:true], @"systemControl", [NSNumber numberWithBool:true], @"PlaySoundFeedback", nil ]; // terminate the list [preferences registerDefaults:dict];
[self setTapping:[preferences boolForKey: @"TappingEnabled"]]; [self setUseAppleCMDModifier:[preferences boolForKey: @"UseAppleCMDModifier"]]; [self setAutomaticUpdates:[preferences boolForKey: @"AutomaticUpdates"]]; [self setHideFromStatusBar:[preferences boolForKey: @"hideFromStatusBarPreference"]]; [self setHideVolumeWindow:[preferences boolForKey: @"hideVolumeWindowPreference"]]; [[self iTunesBtn] setState:[preferences boolForKey: @"iTunesControl"]]; if(osxVersion >= 115) { [[self iTunesBtn] setTitle:@"Music"]; } [[self iTunesBtn] setState:[preferences boolForKey: @"iTunesControl"]]; [[self spotifyBtn] setState:[preferences boolForKey: @"spotifyControl"]]; [[self swinsianBtn] setState:[preferences boolForKey: @"swinsianControl"]]; //[[self systemBtn] setState:[preferences boolForKey: @"systemControl"]]; [[self systemBtn] setState:true]; // hard coded always to true [[self systemBtn] setEnabled:false]; [self setPlaySoundFeedback:[preferences boolForKey: @"PlaySoundFeedback"]];
NSInteger volumeIncSetting = [preferences integerForKey:@"volumeIncrement"]; [self setVolumeInc:volumeIncSetting];
[[self volumeIncrementsSlider] setIntegerValue: volumeIncSetting]; }
(IBAction)toggleAutomaticUpdates:(id)sender { [self setAutomaticUpdates:![self AutomaticUpdates]]; }
(void) setAutomaticUpdates:(bool)enabled { NSMenuItem* menuItem=[_statusMenu itemWithTag:8]; [menuItem setState:enabled];
[preferences setBool:enabled forKey:@"AutomaticUpdates"]; [preferences synchronize];
_AutomaticUpdates=enabled;
[[SUUpdater sharedUpdater] setAutomaticallyChecksForUpdates:enabled]; }
(IBAction)togglePlaySoundFeedback:(id)sender { [self setPlaySoundFeedback:![self PlaySoundFeedback]]; }
(void)setPlaySoundFeedback:(bool)enabled { [preferences setBool:enabled forKey:@"PlaySoundFeedback"]; [preferences synchronize];
NSMenuItem* menuItem=[_statusMenu itemWithTag:7]; [menuItem setState:enabled];
_PlaySoundFeedback=enabled; }
(IBAction)toggleStartAtLogin:(id)sender { [self setStartAtLogin:![self StartAtLogin] savePreferences:true]; }
(void) setUseAppleCMDModifier:(bool)enabled { NSMenuItem* menuItem=[_statusMenu itemWithTag:3]; [menuItem setState:enabled];
[preferences setBool:enabled forKey:@"UseAppleCMDModifier"]; [preferences synchronize];
_UseAppleCMDModifier=enabled; }
(IBAction)toggleUseAppleCMDModifier:(id)sender { [self setUseAppleCMDModifier:![self UseAppleCMDModifier]]; }
(void) setTapping:(bool)enabled { NSMenuItem* menuItem=[_statusMenu itemWithTag:1]; [menuItem setState:enabled];
CGEventTapEnable(eventTap, enabled);
[[[self statusBar] button] setAppearsDisabled:!enabled];
[preferences setBool:enabled forKey:@"TappingEnabled"]; [preferences synchronize];
_Tapping=enabled; }
(IBAction)toggleTapping:(id)sender { [self setTapping:![self Tapping]]; }
(IBAction)sliderValueChanged:(NSSliderCell*)slider { NSInteger volumeIncSetting = [[self volumeIncrementsSlider] integerValue];
[self setVolumeInc:volumeIncSetting];
[preferences setInteger:volumeIncSetting forKey:@"volumeIncrement"]; [preferences synchronize];
}
(void) setVolumeInc:(NSInteger)volumeIncSetting { switch(volumeIncSetting) { case 5: increment = 25; break; case 4: increment = 12.5; break; case 3: increment = 6.25; break; case 2: increment = 3.125; break; case 1: default: increment = 1.5625; break;
} }
(IBAction)aboutPanel:(id)sender { NSDictionary infoDict = [[NSBundle mainBundle] infoDictionary]; NSString version = [infoDict objectForKey:@"CFBundleVersion"]; NSRange range=[version rangeOfString:@"." options:NSBackwardsSearch]; if(version>0) version=[version substringFromIndex:range.location+1];
infoDict = [NSDictionary dictionaryWithObjectsAndKeys: version,@"Version", nil ]; // terminate the list
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [[NSApplication sharedApplication] orderFrontStandardAboutPanelWithOptions:infoDict]; }
(void) receiveWakeNote: (NSNotification*) note { NSLog(@"Received WakeNote: %@", [note name]); [self setTapping:[self Tapping]]; }
(void) dealloc {
}
-(void)resetEventTap { CGEventTapEnable(eventTap, _Tapping); }
(void)resetCurrentPlayer:(NSTimer*)theTimer { [checkPlayerTimer invalidate]; checkPlayerTimer = nil; currentPlayer = nil; }
(id)runningPlayer { if(currentPlayer) return currentPlayer;
checkPlayerTimer = [NSTimer timerWithTimeInterval:checkPlayerTimeout target:self selector:@selector(resetCurrentPlayer:) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:checkPlayerTimer forMode:NSRunLoopCommonModes];
if(_AppleCMDModifierPressed == _UseAppleCMDModifier) { if([_iTunesBtn state] && [iTunes isRunning] && [iTunes playerState] == iTunesEPlSPlaying) { currentPlayer = iTunes; } else if([_spotifyBtn state] && [spotify isRunning] && [spotify playerState] == SpotifyEPlSPlaying) { currentPlayer = spotify; } else if([_swinsianBtn state] && [swinsian isRunning] && [swinsian playerState] == SwinsianEPlSPlaying) { currentPlayer = swinsian; } else if([_systemBtn state]) { currentPlayer = systemAudio; } } else currentPlayer = systemAudio;
return currentPlayer; }
(void)setVolumeUp:(bool)increase { id musicPlayerPnt = [self runningPlayer];
if (musicPlayerPnt != nil) { double volume = [musicPlayerPnt currentVolume];
if([musicPlayerPnt oldVolume]<0) // if it was not mute
{
//volume=[musicProgramPnt soundVolume]+_volumeInc*(increase?1:-1);
volume += (increase?1:-1)*increment;
}
else // if it was mute
{
// [volumeImageLayer setContents:imgVolOn]; // restore the image of the speaker from mute speaker
volume=[musicPlayerPnt oldVolume];
[musicPlayerPnt setOldVolume:-1]; // this says that it is not mute
}
if (volume<0) volume=0;
if (volume>100) volume=100;
OSDGraphic image = (volume > 0)? OSDGraphicSpeaker : OSDGraphicSpeakerMute;
NSInteger numFullBlks = floor(volume/6.25);
NSInteger numQrtsBlks = round((volume-(double)numFullBlks*6.25)/1.5625);
//NSLog(@"%d %d",(int)numFullBlks,(int)numQrtsBlks);
if(!_hideVolumeWindow)
[[self->OSDManager sharedManager] showImage:image onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)(round(((numFullBlks*4+numQrtsBlks)*1.5625)*100)) totalChiclets:(unsigned int)10000 locked:NO];
[musicPlayerPnt setCurrentVolume:volume];
if(self->volumeRampTimer == nil)
[self emitAcousticFeedback:nil];
if( musicPlayerPnt == iTunes)
[self setItunesVolume:volume];
else if( musicPlayerPnt == spotify)
[self setSpotifyVolume:volume];
else if (musicPlayerPnt == swinsian)
[self setSwinsianVolume:volume];
else if( musicPlayerPnt == systemAudio)
[self setSystemVolume:volume];
[self refreshVolumeBar:(int)volume];
} }
(void) setItunesVolume:(NSInteger)volume { if (volume == -1) [[self iTunesPerc] setHidden:YES]; else { [[self iTunesPerc] setHidden:NO]; [[self iTunesPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]]; } }
(void) setSpotifyVolume:(NSInteger)volume { if (volume == -1) [[self spotifyPerc] setHidden:YES]; else { [[self spotifyPerc] setHidden:NO]; [[self spotifyPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]]; } }
(void) setSwinsianVolume:(NSInteger)volume { if (volume == -1) [[self swinsianPerc] setHidden:YES]; else { [[self swinsianPerc] setHidden:NO]; [[self swinsianPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]]; } }
(void) setSystemVolume:(NSInteger)volume { if (volume == -1) [[self systemPerc] setHidden:YES]; else { [[self systemPerc] setHidden:NO]; [[self systemPerc] setStringValue:[NSString stringWithFormat:@"(%d%%)",(int)volume]]; }
}
(void) updatePercentages { if([iTunes isRunning]) [self setItunesVolume:[iTunes currentVolume]]; else [self setItunesVolume:-1];
if([spotify isRunning]) [self setSpotifyVolume:[spotify currentVolume]]; else [self setSpotifyVolume:-1];
if ([swinsian isRunning]) [self setSwinsianVolume:[swinsian currentVolume]]; else [self setSwinsianVolume:-1];
[self setSystemVolume:[systemAudio currentVolume]]; }
(void) refreshVolumeBar:(NSInteger)volume { NSInteger doubleFullRectangles = (NSInteger)round(32.0f * volume / 100.0f); NSInteger fullRectangles=doubleFullRectangles>>1;
[CATransaction begin]; [CATransaction setAnimationDuration: 0.0]; [CATransaction setDisableActions: TRUE];
if(volume==0) { [volumeImageLayer setContents:imgVolOff]; } else { [volumeImageLayer setContents:imgVolOn]; }
CGRect frame;
for(NSInteger i=0; i<fullRectangles; i++) { frame = [volumeBar[i] frame]; frame.size.width=9; [volumeBar[i] setFrame:frame];
[volumeBar[i] setHidden:NO];
} for(NSInteger i=fullRectangles; i<16; i++) { frame = [volumeBar[i] frame]; frame.size.width=9; [volumeBar[i] setFrame:frame];
[volumeBar[i] setHidden:YES];
}
if(fullRectangles*2 != doubleFullRectangles) {
frame = [volumeBar[fullRectangles] frame];
frame.size.width=5;
[volumeBar[fullRectangles] setFrame:frame];
[volumeBar[fullRectangles] setHidden:NO];
}
[CATransaction commit]; }
(IBAction)toggleHideFromStatusBar:(id)sender { [self setHideFromStatusBar:![self hideFromStatusBar]]; if ([self hideFromStatusBar]) [self showHideFromStatusBarHintPopover]; }
(void)setHideFromStatusBar:(bool)enabled { _hideFromStatusBar=enabled;
NSMenuItem* menuItem=[_statusMenu itemWithTag:5]; [menuItem setState:[self hideFromStatusBar]];
[preferences setBool:enabled forKey:@"hideFromStatusBarPreference"]; [preferences synchronize];
if(enabled) { if (![_statusBarHideTimer isValid] && [self statusBar]) { [self setHideFromStatusBarHintLabelWithSeconds:statusBarHideDelay]; _statusBarHideTimer = [NSTimer timerWithTimeInterval:statusBarHideDelay target:self selector:@selector(doHideFromStatusBar:) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:_statusBarHideTimer forMode:NSRunLoopCommonModes]; _hideFromStatusBarHintPopoverUpdateTimer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(updateHideFromStatusBarHintPopover:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:_hideFromStatusBarHintPopoverUpdateTimer forMode:NSRunLoopCommonModes]; } } else { [_hideFromStatusBarHintPopover close]; [_statusBarHideTimer invalidate]; _statusBarHideTimer = nil; [_hideFromStatusBarHintPopoverUpdateTimer invalidate]; _hideFromStatusBarHintPopoverUpdateTimer = nil; } }
(void)doHideFromStatusBar:(NSTimer*)aTimer { [_hideFromStatusBarHintPopoverUpdateTimer invalidate]; _hideFromStatusBarHintPopoverUpdateTimer = nil; _statusBarHideTimer = nil; [_hideFromStatusBarHintPopover close]; [[NSStatusBar systemStatusBar] removeStatusItem:[self statusBar]]; _statusBar = nil;
[self setHideFromStatusBar:true]; }
(void)showHideFromStatusBarHintPopover { if ([_hideFromStatusBarHintPopover isShown]) return;
if (! _hideFromStatusBarHintPopover) { CGRect popoverRect = (CGRect) { .size.width = 250, .size.height = 63 };
_hideFromStatusBarHintLabel = [[NSTextField alloc] initWithFrame:CGRectInset(popoverRect, 10, 10)];
[_hideFromStatusBarHintLabel setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
[_hideFromStatusBarHintLabel setEditable:false];
[_hideFromStatusBarHintLabel setSelectable:false];
[_hideFromStatusBarHintLabel setBezeled:false];
[_hideFromStatusBarHintLabel setBackgroundColor:[NSColor clearColor]];
[_hideFromStatusBarHintLabel setAlignment:NSTextAlignmentCenter];
_hintView = [[NSView alloc] initWithFrame:popoverRect];
[_hintView addSubview:_hideFromStatusBarHintLabel];
_hintVC = [[NSViewController alloc] init];
[_hintVC setView:_hintView];
_hideFromStatusBarHintPopover = [[NSPopover alloc] init];
[_hideFromStatusBarHintPopover setContentViewController:_hintVC];
}
NSStatusBarButton *statusBarButton = [[self statusBar] button]; [_hideFromStatusBarHintPopover showRelativeToRect:[statusBarButton bounds] ofView:statusBarButton preferredEdge:NSMinYEdge]; }
(void)updateHideFromStatusBarHintPopover:(NSTimer)aTimer { NSDate now = [NSDate date]; [self setHideFromStatusBarHintLabelWithSeconds:[[_statusBarHideTimer fireDate] timeIntervalSinceDate:now]]; }
(void)setHideFromStatusBarHintLabelWithSeconds:(NSUInteger)seconds { [_hideFromStatusBarHintLabel setStringValue:[NSString stringWithFormat:@"iTunes Volume Control will hide after %ld seconds. Launch the app again to make the icon reappear in the manubar.",seconds]]; }
(IBAction)toggleMusicPlayer:(id)sender { if (sender == _iTunesBtn) { [preferences setBool:[sender state] forKey:@"iTunesControl"]; } else if (sender == _spotifyBtn) { [preferences setBool:[sender state] forKey:@"spotifyControl"]; } else if (sender == _swinsianBtn) { [preferences setBool:[sender state] forKey:@"swinsianControl"]; }
[preferences synchronize]; }
(IBAction)toggleHideVolumeWindow:(id)sender { [self setHideVolumeWindow:![self hideVolumeWindow]]; }
(void)setHideVolumeWindow:(bool)enabled { _hideVolumeWindow=enabled;
NSMenuItem* menuItem=[_statusMenu itemWithTag:6]; [menuItem setState:[self hideVolumeWindow]];
[preferences setBool:enabled forKey:@"hideVolumeWindowPreference"]; [preferences synchronize]; }
(void)menuWillOpen:(NSMenu *)menu { [self updatePercentages];
if(!_Tapping) { updateSystemVolumeTimer = [NSTimer timerWithTimeInterval:updateSystemVolumeInterval target:self selector:@selector(updateSystemVolume:) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:updateSystemVolumeTimer forMode:NSRunLoopCommonModes]; }
[_hideFromStatusBarHintPopover close]; menuIsVisible=true; }
(void)menuDidClose:(NSMenu *)menu { menuIsVisible=false; if([self hideFromStatusBar]) [self showHideFromStatusBarHintPopover];
if(updateSystemVolumeTimer) { [updateSystemVolumeTimer invalidate]; updateSystemVolumeTimer = nil; } }
@end
I really just changed any Doppler related line to Swinisian. Not as it should be done but i dont need Doppler. Also when inspecting the apple script function list of Swinisian, it says sound volume (number) vs sound volume (integer) as with Music. I dont know if this could be related.
Any updates on this? Still trying to get this to work.
I will eventually give it a try. I am sorry, I cannot promise when. Possibly by the end of July. I hope you will understand.
Any updates on this? Still trying to get this to work.
-- Reply to this email directly or view it on GitHub: https://github.com/alberti42/Volume-Control/issues/25#issuecomment-2206026109 You are receiving this because you commented.
Message ID: @.***>
Ofc, I am trying to fix it myself but I am not really a programmer.
Changing the volume exits with error code. Seems to be something about memory. This only happens when swinsian is actually playing back music. So the good thing: I managed that volume control recognizes swinsian.
However it seems to break inside the function in appdelegate.m
where double vol2 = [musicPlayer soundVolume]; tries to get the @property of Swinsian.h called soundVolume. However since i just replaced the Doppler keywords with Swinsian, @property NSInteger soundVolume; is still defined as NSInteger and I am thinking that Swinsian may not be returning a different type then NSInteger.
using applescript to check Swinsians functions it seems soundVolume is defined as:
sound volume (number) : the volume. (0 minimum, 100 maximum)
whereas applescript says about Music:
sound volume (integer) : the sound output volume (0 = minimum, 100 = maximum)
So I dont know if the invoked apple script is causing this problem or simply because the soundVolume property is hardcoded to be of type NSInteger.
Eventually I'll find out, but maybe you can hint me.
UPDATE: It seems number in applescript actually means float...jeez alright lets go.
I fixed it :)
I'll refactor the code and eventually upload it or send it to you so you can include my code to inlcude swinsian functionality. Just tell me how I can beam it to you :)
Did you test first a simple Applescript to show that you can control the volume?
Unfortunately I would have to look more in detail. Did you try to pass it to chatgpt? Clearly the code was written pre-chat-gpt. But it can really help you.
Ofc, I am trying to fix it myself but I am not really a programmer.
Changing the volume exits with error code. Seems to be something about memory. This only happens when swinsian is actually playing back music. So the good thing: I managed that volume control recognizes swinsian.
However it seems to break inside the function in appdelegate.m
- (double) currentVolume
where double vol2 = [musicPlayer soundVolume]; tries to get the @property of Swinsian.h called soundVolume. However since i just replaced the Doppler keywords with Swinsian, @property NSInteger soundVolume; is still defined as NSInteger and I am thinking that Swinsian may not be returning a different type then NSInteger.
using applescript to check Swinsians functions it seems soundVolume is defined as:
sound volume (number) : the volume. (0 minimum, 100 maximum)
whereas applescript says about Music:
sound volume (integer) : the sound output volume (0 = minimum, 100 = maximum)
So I dont know if the invoked apple script is causing this problem or simply because the soundVolume property is hardcoded to be of type NSInteger.
Eventually I'll find out, but maybe you can hint me.
-- Reply to this email directly or view it on GitHub: https://github.com/alberti42/Volume-Control/issues/25#issuecomment-2206776422 You are receiving this because you commented.
Message ID: @.***>
Sounds great. Congratulations!
Yes, in principle you can open a pull request on git. If it is too complicated, just post the code.
I fixed it :)
I'll refactor the code and eventually upload it or send it to you so you can include my code to inlcude swinsian functionality. Just tell me how I can beam it to you :)
-- Reply to this email directly or view it on GitHub: https://github.com/alberti42/Volume-Control/issues/25#issuecomment-2206820956 You are receiving this because you commented.
Message ID: @.***>
Another update:
as mentioned I addes Swinsian support, however while doing that I broke Music and probably iTunes support.
Swinsian.h: `/*
@class SwinsianTrack, SwinsianApplication;
enum SwinsianEPlS { SwinsianEPlSStopped = 'kPSS', SwinsianEPlSPlaying = 'kPSP', SwinsianEPlSPaused = 'kPSp' }; typedef enum SwinsianEPlS SwinsianEPlS;
/*
// playable track @interface SwinsianTrack : SBObject
(NSString ) id; // the id of the track @property (copy, readonly) NSString name; // the title of the track @property (copy, readonly) NSImage artwork; // a piece of art within a track @property (copy, readonly) NSString album; // the album name of the track @property (copy, readonly) NSString albumArtist; // the album artist of the track @property (copy, readonly) NSString artist; // the artist of the track @property BOOL loved; // is this track loved?
(void) reveal; // reveal and select the specified track
@end
// The application program @interface SwinsianApplication : SBApplication
@property (copy, readonly) SwinsianTrack currentTrack; // the currently playing track @property (readonly) SwinsianEPlS playerState; // the current state of the audio player @property BOOL shuffleEnabled; // are songs played in random order? @property NSNumber soundVolume; // the sound output volume (0 = minimum, 100 = maximum)
@end `
Inside AppDelegate.m, i essentially added a Swinsian statement after every Doppler statment. Just copy and paste and change "doppler" to "swinsian". However as Swinsian returns NSNumber, I changed all the properties for soundVolume of iTunes.h Spotify.h and Doppler.h to be of type NSNumber.
And I modified these two functions in AppDelegate.m `- (void) setCurrentVolume:(double)currentVolume { [self setDoubleVolume:currentVolume]; NSNumber *roundedVolume = [NSNumber numberWithInteger:round(currentVolume)]; [musicPlayer setSoundVolume:roundedVolume]; }
(double)currentVolume { id soundVolume = [musicPlayer soundVolume]; NSLog(@"soundVolume: %@", soundVolume); // Log the returned value
if ([soundVolume isKindOfClass:[NSNumber class]]) { NSInteger volume = [soundVolume intValue]; double vol = (double)volume;
double selfVolume = [self doubleVolume];
NSLog(@"Retrieved volume: %f, Self volume: %f", vol, selfVolume);
if (fabs(vol - selfVolume) < 1) {
vol = selfVolume;
}
return vol;
} else { NSLog(@"soundVolume is not an NSNumber, actual class: %@", [soundVolume class]); return 0.0; } }`
It works when swinsian is running and playing music but this line: id soundVolume = [musicPlayer soundVolume]; immediately fails when music is used for music playback. I suppose its because Music returns NSInteger and NSInteger is not an object but a primitive type. I am not completely sure if thats actually what causes it to fail. Program aborts with: "Thread1:EXC_BAD_ACCESS (code=1, address=0x30)"
Possible solutions might be either to get this type distinction working or to check which app actually is playing atm inside the currentVolume function. Or revert the Properties to type NSInteger and use some fancy bitwise operations to extract the float or int values. I dont know.
Im trying to add Swinsian support but I'm having issues getting it done. I used the Doppler.h and repurposed everything to Swinsian, changed the ApplicationIDHandle in AppDelegate, but no luck so far. Swinsian has a scriptable variable called sound volume, same as iTunes.