Skip to content

Commit

Permalink
Added app volume and pan setting to AppleScript
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcus Wu committed Mar 20, 2021
1 parent 2ff4c08 commit 9765193
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 11 deletions.
6 changes: 6 additions & 0 deletions BGMApp/BGMApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@
27FB8C2F1DE468320084DB9D /* BGM_Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FB8C2E1DE468320084DB9D /* BGM_Utils.cpp */; settings = {COMPILER_FLAGS = "-frandom-seed=BGMApp-BGM_Utils.cpp"; }; };
27FB8C301DE4758A0084DB9D /* BGMPlayThrough.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1C1962E51BC94E91008A4DF7 /* BGMPlayThrough.cpp */; };
27FB8C311DE4758A0084DB9D /* BGM_Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27FB8C2E1DE468320084DB9D /* BGM_Utils.cpp */; };
9E129A412602AE620005851B /* BGMASApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 9E129A402602AE620005851B /* BGMASApplication.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -433,6 +434,8 @@
27F7D48F1D2483B100821C4B /* BGMDecibel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BGMDecibel.m; path = "Music Players/BGMDecibel.m"; sourceTree = "<group>"; };
27F7D4911D2484A300821C4B /* Decibel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Decibel.h; path = "Music Players/Decibel.h"; sourceTree = "<group>"; };
27FB8C2E1DE468320084DB9D /* BGM_Utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BGM_Utils.cpp; path = ../SharedSource/BGM_Utils.cpp; sourceTree = "<group>"; };
9E129A3F2602AE620005851B /* BGMASApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BGMASApplication.h; path = Scripting/BGMASApplication.h; sourceTree = "<group>"; };
9E129A402602AE620005851B /* BGMASApplication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = BGMASApplication.m; path = Scripting/BGMASApplication.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -562,6 +565,8 @@
1C2FC31D1EC723A100A76592 /* BGMASOutputDevice.h */,
1C2FC31A1EC7238A00A76592 /* BGMASOutputDevice.mm */,
1C2FC2FF1EB4D6E700A76592 /* BGMApp.sdef */,
9E129A3F2602AE620005851B /* BGMASApplication.h */,
9E129A402602AE620005851B /* BGMASApplication.m */,
);
name = Scripting;
sourceTree = "<group>";
Expand Down Expand Up @@ -1152,6 +1157,7 @@
1C837DD81F6AA1F2004B1E60 /* BGMOutputVolumeMenuItem.mm in Sources */,
1C9258472090287F00B8D3A6 /* BGMGooglePlayMusicDesktopPlayerConnection.m in Sources */,
1C1963011BCAC0F6008A4DF7 /* CACFString.cpp in Sources */,
9E129A412602AE620005851B /* BGMASApplication.m in Sources */,
1C1962E71BC94E91008A4DF7 /* BGMPlayThrough.cpp in Sources */,
1C8D8304204238DB00A838F2 /* BGMSwinsian.m in Sources */,
1C1962FA1BCAC061008A4DF7 /* CADebugMacros.cpp in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions BGMApp/BGMApp/BGMAppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

// Local Includes
#import "BGMAudioDeviceManager.h"
#import "BGMAppVolumesController.h"

// System Includes
#import <Cocoa/Cocoa.h>
Expand Down Expand Up @@ -53,6 +54,7 @@ static NSInteger const kSeparatorBelowVolumesMenuItemTag = 4;
@property (weak) IBOutlet NSMenuItem* debugLoggingMenuItemUnwrapped;

@property (readonly) BGMAudioDeviceManager* audioDevices;
@property BGMAppVolumesController* appVolumes;

@end

2 changes: 1 addition & 1 deletion BGMApp/BGMApp/BGMAppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ @implementation BGMAppDelegate {
BGMAutoPauseMenuItem* autoPauseMenuItem;
BGMMusicPlayers* musicPlayers;
BGMSystemSoundsVolume* systemSoundsVolume;
BGMAppVolumesController* appVolumes;
BGMOutputDeviceMenuSection* outputDeviceMenuSection;
BGMPreferencesMenu* prefsMenu;
BGMDebugLoggingMenuItem* debugLoggingMenuItem;
Expand All @@ -73,6 +72,7 @@ @implementation BGMAppDelegate {
}

@synthesize audioDevices = audioDevices;
@synthesize appVolumes = appVolumes;

- (void) awakeFromNib {
[super awakeFromNib];
Expand Down
3 changes: 3 additions & 0 deletions BGMApp/BGMApp/BGMAppVolumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@

- (void) removeAllAppVolumeMenuItems;

- (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication*)app;
- (void) setVolumeAndPan:(BGMAppVolumeAndPan)volumeAndPan forApp:(NSRunningApplication*)app;

@end

// Protocol for the UI custom classes
Expand Down
73 changes: 73 additions & 0 deletions BGMApp/BGMApp/BGMAppVolumes.m
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,79 @@ - (void) insertMenuItemForApp:(NSRunningApplication*)app
}
}

- (NSMenuItem*) getMenuItemForApp:(NSRunningApplication*)app {
NSInteger lastAppVolumeMenuItemIndex = [self lastMenuItemIndex] - 2;

for (NSInteger i = [self firstMenuItemIndex]; i <= lastAppVolumeMenuItemIndex; i++) {
NSMenuItem* item = [bgmMenu itemAtIndex:i];
NSRunningApplication* itemApp = item.representedObject;
BGMAssert(itemApp, "!itemApp for %s", item.title.UTF8String);

if ([itemApp isEqual:app]) {
return item;
}
}
for (NSInteger i = 0; i < [moreAppsMenu numberOfItems]; i++) {
NSMenuItem* item = [moreAppsMenu itemAtIndex:i];
NSRunningApplication* itemApp = item.representedObject;
BGMAssert(itemApp, "!itemApp for %s", item.title.UTF8String);

if ([itemApp isEqual:app]) {
return item;
}
}

return nil;
}

- (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication*)app {
BGMAppVolumeAndPan result = {
.volume = -1,
.pan = -1
};

NSMenuItem *item = [self getMenuItemForApp:app];

if (item == nil) {
return result;
}

for (NSView* subview in item.view.subviews) {
// Get the volume.
if ([subview isKindOfClass:[BGMAVM_VolumeSlider class]]) {
result.volume = [(BGMAVM_VolumeSlider*)subview intValue];
}

// Get the pan position.
if ([subview isKindOfClass:[BGMAVM_PanSlider class]]) {
result.pan = [(BGMAVM_PanSlider*)subview intValue];
}
}

return result;
}

- (void) setVolumeAndPan:(BGMAppVolumeAndPan)volumeAndPan forApp:(NSRunningApplication*)app {
NSMenuItem *item = [self getMenuItemForApp:app];

if (item == nil) {
return;
}

for (NSView* subview in item.view.subviews) {
// Get the volume.
if (volumeAndPan.volume != -1 && [subview isKindOfClass:[BGMAVM_VolumeSlider class]]) {
[(BGMAVM_VolumeSlider*)subview setRelativeVolume:volumeAndPan.volume];
}

// Get the pan position.
if (volumeAndPan.pan != -1 && [subview isKindOfClass:[BGMAVM_PanSlider class]]) {
[(BGMAVM_PanSlider*)subview setPanPosition:volumeAndPan.pan];
}
}

}

// Create a blank menu item to copy as a template.
- (NSMenuItem*) createBlankAppVolumeMenuItem {
NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
Expand Down
8 changes: 8 additions & 0 deletions BGMApp/BGMApp/BGMAppVolumesController.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@

#pragma clang assume_nonnull begin

typedef struct BGMAppVolumeAndPan {
int volume;
int pan;
} BGMAppVolumeAndPan;

@interface BGMAppVolumesController : NSObject

- (id) initWithMenu:(NSMenu*)menu
Expand All @@ -45,6 +50,9 @@ forAppWithProcessID:(pid_t)processID
forAppWithProcessID:(pid_t)processID
bundleID:(NSString* __nullable)bundleID;

- (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication *)app;
- (void) setVolumeAndPan:(BGMAppVolumeAndPan)volumeAndPan forApp:(NSRunningApplication*)app;

@end

#pragma clang assume_nonnull end
Expand Down
19 changes: 14 additions & 5 deletions BGMApp/BGMApp/BGMAppVolumesController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@

#pragma clang assume_nonnull begin

typedef struct BGMAppVolumeAndPan {
int volume;
int pan;
} BGMAppVolumeAndPan;

@implementation BGMAppVolumesController {
// The App Volumes UI.
BGMAppVolumes* appVolumes;
Expand Down Expand Up @@ -104,6 +99,20 @@ - (void) insertMenuItemsForApps:(NSArray<NSRunningApplication*>*)apps {
}
}

- (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication *)app {
return [appVolumes getVolumeAndPanForApp:app];
}

- (void) setVolumeAndPan:(BGMAppVolumeAndPan)volumeAndPan forApp:(NSRunningApplication*)app {
[appVolumes setVolumeAndPan:volumeAndPan forApp:app];
if (volumeAndPan.volume != -1) {
[self setVolume:volumeAndPan.volume forAppWithProcessID:app.processIdentifier bundleID:app.bundleIdentifier];
}
if (volumeAndPan.pan != -1) {
[self setPanPosition:volumeAndPan.pan forAppWithProcessID:app.processIdentifier bundleID:app.bundleIdentifier];
}
}

- (BGMAppVolumeAndPan) getVolumeAndPanForApp:(NSRunningApplication*)app
fromVolumes:(const CACFArray&)volumes {
BGMAppVolumeAndPan volumeAndPan = {
Expand Down
31 changes: 31 additions & 0 deletions BGMApp/BGMApp/Scripting/BGMASApplication.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// BGMASApplication.h
// Background Music
//
// Created by Marcus Wu on 3/17/21.
// Copyright © 2021 Background Music contributors. All rights reserved.
//

// Local Includes
#import "BGMAppVolumesController.h"

// System Includes
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>


NS_ASSUME_NONNULL_BEGIN

@interface BGMASApplication : NSObject

- (instancetype) initWithApplication:(NSRunningApplication*)app
volumeController:(BGMAppVolumesController*)volumeController
parentSpecifier:(NSScriptObjectSpecifier* __nullable)parentSpecifier
index:(int)i;

@property (readonly) NSString* name;
@property int volume;
@property int pan;
@end

NS_ASSUME_NONNULL_END
69 changes: 69 additions & 0 deletions BGMApp/BGMApp/Scripting/BGMASApplication.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//
// BGMASApplication.m
// Background Music
//
// Created by Marcus Wu on 3/17/21.
// Copyright © 2021 Background Music contributors. All rights reserved.
//

// Self Include
#import "BGMASApplication.h"

@implementation BGMASApplication {
NSScriptObjectSpecifier* parentSpecifier;
NSRunningApplication *application;
BGMAppVolumesController* appVolumesController;
int index;
}

- (instancetype) initWithApplication:(NSRunningApplication*)app
volumeController:(BGMAppVolumesController*)volumeController
parentSpecifier:(NSScriptObjectSpecifier* __nullable)parent
index:(int)i {
if ((self = [super init])) {
parentSpecifier = parent;
application = app;
appVolumesController = volumeController;
index = i;
}

return self;
}

- (NSString*) name {
return [NSString stringWithFormat:@"%@", [application localizedName]];
}

- (int) volume {
return [appVolumesController getVolumeAndPanForApp:application].volume;
}

- (void) setVolume:(int)vol {
BGMAppVolumeAndPan volume = {
.volume = vol,
.pan = -1
};
[appVolumesController setVolumeAndPan:volume forApp:application];
}

- (int) pan {
return [appVolumesController getVolumeAndPanForApp:application].pan;
}

- (void) setPan:(int)pan {
BGMAppVolumeAndPan thePan = {
.volume = -1,
.pan = pan
};
[appVolumesController setVolumeAndPan:thePan forApp:application];
}

- (NSScriptObjectSpecifier* __nullable) objectSpecifier {
NSScriptClassDescription* parentClassDescription = [parentSpecifier keyClassDescription];
return [[NSNameSpecifier alloc] initWithContainerClassDescription:parentClassDescription
containerSpecifier:parentSpecifier
key:@"applications"
name:self.name];
}

@end
54 changes: 50 additions & 4 deletions BGMApp/BGMApp/Scripting/BGMApp.sdef
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
<class name="output device"
code="aDev"
description="A hardware device that can play audio"
plural="output devices"
inherits="item">
plural="output devices">
<synonym name="audio device"/>

<cocoa class="BGMASOutputDevice"/>
Expand All @@ -19,14 +18,49 @@
code="pnam"
description="The name of the output device."
type="text"
access="r"/>
access="r">
<cocoa key="name"/>
</property>

<property name="selected"
code="Slcd"
type="boolean"
access="rw"
description="Is this the device to be used for audio output?">
<synonym name="default"/>
<cocoa key="selected"/>
</property>
</class>

<class name="audio application"
code="aApp"
description="An application that can play audio"
plural="audio applications">
<synonym name="audio app"/>

<cocoa class="BGMASApplication"/>

<property name="name"
code="pnam"
description="The name of the application."
type="text"
access="r">
<cocoa key="name"/>
</property>

<property name="vol"
code="pVol"
type="integer"
access="rw"
description="The volume setting of the application">
<cocoa key="volume"/>
</property>

<property name="pan"
code="pPan"
type="integer"
access="rw"
description="The pan setting of the application">
<cocoa key="pan"/>
</property>
</class>

Expand All @@ -48,11 +82,23 @@

<cocoa key="selectedOutputDevice"/>
</property>
<property name="output volume"
type="real"
code="oVol"
access="rw"
description="The main output volume">
<synonym name="main volume"/>

<cocoa key="mainVolume"/>
</property>

<!-- Unintuitively, this is for the array of output devices. -->
<element type="output device" access="r">
<cocoa key="outputDevices"/>
</element>
<element type="audio application" access="r">
<cocoa key="applications"/>
</element>
</class>
</suite>
</dictionary>
Expand Down
Loading

0 comments on commit 9765193

Please sign in to comment.