Move the pan sliders into an "extra controls" section of the menu items.
Also add centre tick marks and "L"/"R" (left/right) labels to them. The idea is to eventually include extra controls like an equalizer, recording apps, hiding/ignoring apps, routing apps, etc. Also, remove the left margin from the App Volumes menu items. Even macOS isn't consistent about including that margin, as far as I can tell.
This commit is contained in:
@@ -35,40 +35,32 @@
|
||||
|
||||
// Protocol for the UI custom classes
|
||||
|
||||
@protocol BGMAppVolumeSubview <NSObject>
|
||||
@protocol BGMAppVolumeMenuItemSubview <NSObject>
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx;
|
||||
|
||||
@end
|
||||
|
||||
@protocol BGMAppPanSubview <NSObject>
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx;
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx menuItem:(NSMenuItem*)item;
|
||||
|
||||
@end
|
||||
|
||||
// Custom classes for the UI elements in the app volume menu items
|
||||
|
||||
@interface BGMAVM_AppIcon : NSImageView <BGMAppVolumeSubview>
|
||||
@interface BGMAVM_AppIcon : NSImageView <BGMAppVolumeMenuItemSubview>
|
||||
@end
|
||||
|
||||
@interface BGMAVM_AppNameLabel : NSTextField <BGMAppVolumeSubview>
|
||||
@interface BGMAVM_AppNameLabel : NSTextField <BGMAppVolumeMenuItemSubview>
|
||||
@end
|
||||
|
||||
@interface BGMAVM_VolumeSlider : NSSlider <BGMAppVolumeSubview>
|
||||
@interface BGMAVM_ShowMoreControlsButton : NSButton <BGMAppVolumeMenuItemSubview>
|
||||
@end
|
||||
|
||||
@interface BGMAVM_VolumeSlider : NSSlider <BGMAppVolumeMenuItemSubview>
|
||||
|
||||
- (void) setRelativeVolume:(NSNumber*)relativeVolume;
|
||||
|
||||
@end
|
||||
|
||||
@interface BGMAVM_PanSlider : NSSlider <BGMAppPanSubview>
|
||||
@interface BGMAVM_PanSlider : NSSlider <BGMAppVolumeMenuItemSubview>
|
||||
|
||||
- (void) setPanPosition:(NSNumber*)panPosition;
|
||||
|
||||
@end
|
||||
|
||||
@interface BGMAVM_PanSliderCell : NSSliderCell
|
||||
|
||||
- (void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped;
|
||||
|
||||
@end
|
||||
|
||||
+124
-74
@@ -17,7 +17,8 @@
|
||||
// BGMAppVolumes.m
|
||||
// BGMApp
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Copyright © 2016, 2017 Kyle Neideck
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
//
|
||||
|
||||
// Self Include
|
||||
@@ -25,6 +26,7 @@
|
||||
|
||||
// BGM Includes
|
||||
#include "BGM_Types.h"
|
||||
#include "BGM_Utils.h"
|
||||
|
||||
// PublicUtility Includes
|
||||
#include "CACFDictionary.h"
|
||||
@@ -32,14 +34,20 @@
|
||||
#include "CACFString.h"
|
||||
|
||||
|
||||
static NSInteger const kAppVolumesMenuItemTag = 3;
|
||||
// Tags for UI elements in MainMenu.xib
|
||||
static NSInteger const kAppVolumesHeadingMenuItemTag = 3;
|
||||
static NSInteger const kSeparatorBelowAppVolumesMenuItemTag = 4;
|
||||
|
||||
static float const kSlidersSnapWithin = 5;
|
||||
|
||||
static CGFloat const kAppVolumeViewInitialHeight = 20;
|
||||
|
||||
@implementation BGMAppVolumes {
|
||||
NSMenu* bgmMenu;
|
||||
|
||||
NSView* appVolumeView;
|
||||
CGFloat appVolumeViewFullHeight;
|
||||
|
||||
BGMAudioDeviceManager* audioDevices;
|
||||
}
|
||||
|
||||
@@ -47,6 +55,7 @@ static float const kSlidersSnapWithin = 5;
|
||||
if ((self = [super init])) {
|
||||
bgmMenu = menu;
|
||||
appVolumeView = view;
|
||||
appVolumeViewFullHeight = appVolumeView.frame.size.height;
|
||||
audioDevices = devices;
|
||||
|
||||
// Create the menu items for controlling app volumes
|
||||
@@ -66,23 +75,26 @@ static float const kSlidersSnapWithin = 5;
|
||||
[[NSWorkspace sharedWorkspace] removeObserver:self forKeyPath:@"runningApplications" context:nil];
|
||||
}
|
||||
|
||||
#pragma mark UI Modifications
|
||||
|
||||
- (void) insertMenuItemsForApps:(NSArray<NSRunningApplication*>*)apps {
|
||||
NSAssert([NSThread isMainThread], @"insertMenuItemsForApps is not thread safe");
|
||||
|
||||
#ifndef NS_BLOCK_ASSERTIONS // If assertions are enabled
|
||||
NSInteger numMenuItemsBeforeInsert =
|
||||
[bgmMenu indexOfItemWithTag:kSeparatorBelowAppVolumesMenuItemTag] - [bgmMenu indexOfItemWithTag:kAppVolumesMenuItemTag] - 1;
|
||||
auto numMenuItems = [&self]() {
|
||||
NSInteger headingIdx = [bgmMenu indexOfItemWithTag:kAppVolumesHeadingMenuItemTag];
|
||||
NSInteger separatorIdx = [bgmMenu indexOfItemWithTag:kSeparatorBelowAppVolumesMenuItemTag];
|
||||
return separatorIdx - headingIdx - 1;
|
||||
};
|
||||
|
||||
NSInteger numMenuItemsBeforeInsert = numMenuItems();
|
||||
NSUInteger numApps = 0;
|
||||
#endif
|
||||
|
||||
// Create a blank menu item to copy as a template
|
||||
NSMenuItem* blankItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
blankItem.view = appVolumeView;
|
||||
|
||||
// Get the app volumes currently set on the device
|
||||
CACFArray appVolumesOnDevice((CFArrayRef)[audioDevices bgmDevice].GetPropertyData_CFType(kBGMAppVolumesAddress), false);
|
||||
|
||||
NSInteger index = [bgmMenu indexOfItemWithTag:kAppVolumesMenuItemTag] + 1;
|
||||
NSInteger index = [bgmMenu indexOfItemWithTag:kAppVolumesHeadingMenuItemTag] + 1;
|
||||
|
||||
// Add a volume-control menu item for each app
|
||||
for (NSRunningApplication* app in apps) {
|
||||
@@ -95,15 +107,12 @@ static float const kSlidersSnapWithin = 5;
|
||||
numApps++;
|
||||
#endif
|
||||
|
||||
NSMenuItem* appVolItem = [blankItem copy];
|
||||
NSMenuItem* appVolItem = [self createBlankAppVolumeMenuItem];
|
||||
|
||||
// Look through the menu item's subviews for the ones we want to set up
|
||||
for (NSView* subview in appVolItem.view.subviews) {
|
||||
if ([subview conformsToProtocol:@protocol(BGMAppVolumeSubview)]) {
|
||||
[subview performSelector:@selector(setUpWithApp:context:) withObject:app withObject:self];
|
||||
}
|
||||
if ([subview conformsToProtocol:@protocol(BGMAppPanSubview)]) {
|
||||
[subview performSelector:@selector(setUpWithApp:context:) withObject:app withObject:self];
|
||||
if ([subview conformsToProtocol:@protocol(BGMAppVolumeMenuItemSubview)]) {
|
||||
[(NSView<BGMAppVolumeMenuItemSubview>*)subview setUpWithApp:app context:self menuItem:appVolItem];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,21 +125,27 @@ static float const kSlidersSnapWithin = 5;
|
||||
[bgmMenu insertItem:appVolItem atIndex:index];
|
||||
}
|
||||
|
||||
#ifndef NS_BLOCK_ASSERTIONS // If assertions are enabled
|
||||
NSInteger numMenuItemsAfterInsert =
|
||||
[bgmMenu indexOfItemWithTag:kSeparatorBelowAppVolumesMenuItemTag] - [bgmMenu indexOfItemWithTag:kAppVolumesMenuItemTag] - 1;
|
||||
NSAssert3(numMenuItemsAfterInsert == (numMenuItemsBeforeInsert + numApps),
|
||||
@"Did not add the expected number of menu items. numMenuItemsBeforeInsert=%ld numMenuItemsAfterInsert=%ld numAppsToAdd=%lu",
|
||||
NSAssert3(numMenuItems() == (numMenuItemsBeforeInsert + numApps),
|
||||
@"Added more/fewer menu items than there were apps. Items before: %ld, items after: %ld, apps: %lu",
|
||||
(long)numMenuItemsBeforeInsert,
|
||||
(long)numMenuItemsAfterInsert,
|
||||
(long)numMenuItems(),
|
||||
(unsigned long)numApps);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create a blank menu item to copy as a template.
|
||||
- (NSMenuItem*) createBlankAppVolumeMenuItem {
|
||||
NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
|
||||
|
||||
menuItem.view = appVolumeView;
|
||||
menuItem = [menuItem copy]; // So we can modify a copy of the view, rather than the template itself.
|
||||
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
- (void) removeMenuItemsForApps:(NSArray<NSRunningApplication*>*)apps {
|
||||
NSAssert([NSThread isMainThread], @"removeMenuItemsForApps is not thread safe");
|
||||
|
||||
NSInteger firstItemIndex = [bgmMenu indexOfItemWithTag:kAppVolumesMenuItemTag] + 1;
|
||||
NSInteger firstItemIndex = [bgmMenu indexOfItemWithTag:kAppVolumesHeadingMenuItemTag] + 1;
|
||||
NSInteger lastItemIndex = [bgmMenu indexOfItemWithTag:kSeparatorBelowAppVolumesMenuItemTag] - 1;
|
||||
|
||||
// Check each app volume menu item, removing the items that control one of the given apps
|
||||
@@ -188,6 +203,55 @@ static float const kSlidersSnapWithin = 5;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) showHideExtraControls:(BGMAVM_ShowMoreControlsButton*)button {
|
||||
// Show or hide an app's extra controls, currently only pan, in its App Volumes menu item.
|
||||
|
||||
NSMenuItem* menuItem = button.cell.representedObject;
|
||||
|
||||
BGMAssert(button, "!button");
|
||||
BGMAssert(menuItem, "!menuItem");
|
||||
|
||||
CGFloat width = menuItem.view.frame.size.width;
|
||||
CGFloat height = menuItem.view.frame.size.height;
|
||||
|
||||
#if DEBUG
|
||||
const char* appName = [((NSRunningApplication*)menuItem.representedObject).localizedName UTF8String];
|
||||
#endif
|
||||
|
||||
auto nearEnough = [](CGFloat x, CGFloat y) { // Shouldn't be necessary, but just in case.
|
||||
return fabs(x - y) < 0.01; // We don't need much precision.
|
||||
};
|
||||
|
||||
if (nearEnough(button.frameCenterRotation, 0.0)) {
|
||||
// Hide extra controls
|
||||
DebugMsg("BGMAppVolumes::showHideExtraControls: Hiding extra controls (%s)", appName);
|
||||
|
||||
BGMAssert(nearEnough(height, appVolumeViewFullHeight), "Extra controls were already hidden");
|
||||
|
||||
// Make the menu item shorter to hide the extra controls. Keep the width unchanged.
|
||||
menuItem.view.frameSize = { width, kAppVolumeViewInitialHeight };
|
||||
// Turn the button upside down so the arrowhead points down.
|
||||
button.frameCenterRotation = 180.0;
|
||||
// Move the button up slightly so it aligns with the volume slider.
|
||||
[button setFrameOrigin:NSMakePoint(button.frame.origin.x, button.frame.origin.y - 1)];
|
||||
} else {
|
||||
// Show extra controls
|
||||
DebugMsg("BGMAppVolumes::showHideExtraControls: Showing extra controls (%s)", appName);
|
||||
|
||||
BGMAssert(nearEnough(button.frameCenterRotation, 180.0), "Unexpected button rotation");
|
||||
BGMAssert(nearEnough(height, kAppVolumeViewInitialHeight), "Extra controls were already shown");
|
||||
|
||||
// Make the menu item taller to show the extra controls. Keep the width unchanged.
|
||||
menuItem.view.frameSize = { width, appVolumeViewFullHeight };
|
||||
// Turn the button rightside up so the arrowhead points up.
|
||||
button.frameCenterRotation = 0.0;
|
||||
// Move the button down slightly, back to it's original position.
|
||||
[button setFrameOrigin:NSMakePoint(button.frame.origin.x, button.frame.origin.y + 1)];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark KVO
|
||||
|
||||
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
{
|
||||
#pragma unused (object, context)
|
||||
@@ -220,6 +284,8 @@ static float const kSlidersSnapWithin = 5;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark BGMDevice Communication
|
||||
|
||||
- (void) sendVolumeChangeToBGMDevice:(SInt32)newVolume appProcessID:(pid_t)appProcessID appBundleID:(NSString*)appBundleID {
|
||||
CACFDictionary appVolumeChange(true);
|
||||
appVolumeChange.AddSInt32(CFSTR(kBGMAppVolumesKey_ProcessID), appProcessID);
|
||||
@@ -246,14 +312,17 @@ static float const kSlidersSnapWithin = 5;
|
||||
|
||||
[audioDevices bgmDevice].SetPropertyData_CFType(kBGMAppVolumesAddress, appVolumeChanges.AsPropertyList());
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark Custom Classes (IB)
|
||||
|
||||
// Custom classes for the UI elements in the app volume menu items
|
||||
|
||||
@implementation BGMAVM_AppIcon
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx {
|
||||
#pragma unused (ctx)
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx menuItem:(NSMenuItem*)menuItem {
|
||||
#pragma unused (ctx, menuItem)
|
||||
|
||||
self.image = app.icon;
|
||||
}
|
||||
@@ -262,8 +331,8 @@ static float const kSlidersSnapWithin = 5;
|
||||
|
||||
@implementation BGMAVM_AppNameLabel
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx {
|
||||
#pragma unused (ctx)
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx menuItem:(NSMenuItem*)menuItem {
|
||||
#pragma unused (ctx, menuItem)
|
||||
|
||||
NSString* name = app.localizedName ? (NSString*)app.localizedName : @"";
|
||||
self.stringValue = name;
|
||||
@@ -271,6 +340,26 @@ static float const kSlidersSnapWithin = 5;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BGMAVM_ShowMoreControlsButton
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx menuItem:(NSMenuItem*)menuItem {
|
||||
#pragma unused (app)
|
||||
|
||||
// Set up the button that show/hide the extra controls (currently only a pan slider) for the app.
|
||||
self.cell.representedObject = menuItem;
|
||||
self.target = ctx;
|
||||
self.action = @selector(showHideExtraControls:);
|
||||
|
||||
// The menu item starts out with the extra controls visible, so we hide them here.
|
||||
//
|
||||
// TODO: Leave them visible if any of the controls are set to non-default values. The user has no way to
|
||||
// tell otherwise. Maybe we should also make this button look different if the controls are hidden
|
||||
// when they have non-default values.
|
||||
[ctx showHideExtraControls:self];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation BGMAVM_VolumeSlider {
|
||||
// Will be set to -1 for apps without a pid
|
||||
pid_t appProcessID;
|
||||
@@ -278,7 +367,9 @@ static float const kSlidersSnapWithin = 5;
|
||||
BGMAppVolumes* context;
|
||||
}
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx {
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx menuItem:(NSMenuItem*)menuItem {
|
||||
#pragma unused (menuItem)
|
||||
|
||||
context = ctx;
|
||||
|
||||
self.target = self;
|
||||
@@ -291,8 +382,10 @@ static float const kSlidersSnapWithin = 5;
|
||||
self.minValue = kAppRelativeVolumeMinRawValue;
|
||||
}
|
||||
|
||||
// We have to handle snapping for volume sliders ourselves because adding a tick mark (snap point) in Interface Builder
|
||||
// changes how the slider looks.
|
||||
- (void) snap {
|
||||
// Snap to the 50% point
|
||||
// Snap to the 50% point.
|
||||
float midPoint = static_cast<float>((self.maxValue + self.minValue) / 2);
|
||||
if (self.floatValue > (midPoint - kSlidersSnapWithin) && self.floatValue < (midPoint + kSlidersSnapWithin)) {
|
||||
self.floatValue = midPoint;
|
||||
@@ -323,26 +416,9 @@ static float const kSlidersSnapWithin = 5;
|
||||
BGMAppVolumes* context;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)coder {
|
||||
self = [super initWithCoder: coder];
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx menuItem:(NSMenuItem*)menuItem {
|
||||
#pragma unused (menuItem)
|
||||
|
||||
if(self) {
|
||||
NSSliderCell * oldCell = [self cell];
|
||||
|
||||
BGMAVM_PanSliderCell *cell = [[BGMAVM_PanSliderCell alloc] init];
|
||||
|
||||
cell.minValue = oldCell.minValue;
|
||||
cell.maxValue = oldCell.maxValue;
|
||||
cell.intValue = oldCell.intValue;
|
||||
cell.controlSize = oldCell.controlSize;
|
||||
|
||||
[self setCell:cell];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) setUpWithApp:(NSRunningApplication*)app context:(BGMAppVolumes*)ctx {
|
||||
context = ctx;
|
||||
|
||||
self.target = self;
|
||||
@@ -355,17 +431,8 @@ static float const kSlidersSnapWithin = 5;
|
||||
self.maxValue = kAppPanRightRawValue;
|
||||
}
|
||||
|
||||
- (void) snap {
|
||||
// Snap to the center point
|
||||
float midPoint = static_cast<float>((self.maxValue + self.minValue) / 2);
|
||||
if (self.floatValue > (midPoint - 2 * kSlidersSnapWithin) && self.floatValue < (midPoint + 2 * kSlidersSnapWithin)) {
|
||||
self.floatValue = midPoint;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setPanPosition:(NSNumber *)panPosition {
|
||||
self.intValue = panPosition.intValue;
|
||||
[self snap];
|
||||
}
|
||||
|
||||
- (void) appPanPositionChanged {
|
||||
@@ -373,25 +440,8 @@ static float const kSlidersSnapWithin = 5;
|
||||
|
||||
DebugMsg("BGMAppVolumes::appPanPositionChanged: App pan position for %s changed to %d", appBundleID.UTF8String, self.intValue);
|
||||
|
||||
[self snap];
|
||||
|
||||
[context sendPanPositionChangeToBGMDevice:self.intValue appProcessID:appProcessID appBundleID:appBundleID];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation BGMAVM_PanSliderCell
|
||||
|
||||
- (void)drawBarInside:(NSRect)rect flipped:(BOOL)flipped {
|
||||
// Custom slider cell to get rid of the level highlight
|
||||
|
||||
// Just run the stock method with the values swapped to get it to do what we want
|
||||
auto savedValue = self.doubleValue;
|
||||
self.doubleValue = self.minValue;
|
||||
[super drawBarInside:rect flipped:flipped];
|
||||
self.doubleValue = savedValue;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D17a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<development version="7000" identifier="xcode"/>
|
||||
@@ -60,12 +60,12 @@
|
||||
</items>
|
||||
<point key="canvasLocation" x="-184" y="-69.5"/>
|
||||
</menu>
|
||||
<customView id="MWB-XH-kFI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="355" height="20"/>
|
||||
<customView wantsLayer="YES" id="MWB-XH-kFI">
|
||||
<rect key="frame" x="0.0" y="0.0" width="269" height="47"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<textField identifier="AppName" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Xmd-bg-huG" customClass="BGMAVM_AppNameLabel">
|
||||
<rect key="frame" x="58" y="4" width="115" height="14"/>
|
||||
<rect key="frame" x="42" y="28" width="115" height="14"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingTail" allowsUndo="NO" sendsActionOnEndEditing="YES" alignment="left" title="App name here" usesSingleLineMode="YES" id="ZHF-ZW-Oqg">
|
||||
<font key="font" metaFont="smallSystem"/>
|
||||
@@ -74,28 +74,66 @@
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<imageView identifier="AppIcon" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="W04-iT-IUw" customClass="BGMAVM_AppIcon">
|
||||
<rect key="frame" x="36" y="3" width="16" height="16"/>
|
||||
<rect key="frame" x="20" y="27" width="16" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" id="6QQ-oO-HxF"/>
|
||||
</imageView>
|
||||
<slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="I1l-Ci-4md" customClass="BGMAVM_VolumeSlider">
|
||||
<rect key="frame" x="179" y="2" width="74" height="15"/>
|
||||
<rect key="frame" x="163" y="27" width="74" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<sliderCell key="cell" controlSize="small" continuous="YES" state="on" alignment="left" maxValue="100" doubleValue="50" tickMarkPosition="above" sliderType="linear" id="Jmg-df-9Xl"/>
|
||||
<accessibility description="Volume"/>
|
||||
</slider>
|
||||
<slider verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2mh-uO-kOV" customClass="BGMAVM_PanSlider">
|
||||
<rect key="frame" x="261" y="2" width="74" height="15"/>
|
||||
<slider toolTip="Pan" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2mh-uO-kOV" customClass="BGMAVM_PanSlider">
|
||||
<rect key="frame" x="163" y="7" width="74" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<sliderCell key="cell" controlSize="small" continuous="YES" state="on" alignment="left" minValue="-100" maxValue="100" tickMarkPosition="above" sliderType="linear" id="ccM-Mt-93g"/>
|
||||
<sliderCell key="cell" controlSize="mini" continuous="YES" state="on" alignment="left" minValue="-100" maxValue="100" tickMarkPosition="below" numberOfTickMarks="1" sliderType="linear" id="ccM-Mt-93g"/>
|
||||
<accessibility description="Pan"/>
|
||||
</slider>
|
||||
<button verticalHuggingPriority="750" fixedFrame="YES" tag="1" springLoaded="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vTG-n6-GxY" customClass="BGMAVM_ShowMoreControlsButton">
|
||||
<rect key="frame" x="243" y="27" width="15" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<contentFilters>
|
||||
<ciFilter name="CIAffineTransform">
|
||||
<configuration>
|
||||
<null key="inputImage"/>
|
||||
<affineTransform key="inputTransform" m11="1" m12="0.0" m21="0.0" m22="1" tX="0.0" tY="2"/>
|
||||
</configuration>
|
||||
</ciFilter>
|
||||
</contentFilters>
|
||||
<buttonCell key="cell" type="square" title="⌃" bezelStyle="shadowlessSquare" image="F928CF85-B22A-4634-8160-BC84F45043E3" alignment="center" lineBreakMode="truncatingTail" imageScaling="proportionallyDown" inset="2" id="IXo-C7-3uE">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<textField toolTip="Pan" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9jc-9i-jw2">
|
||||
<rect key="frame" x="162" y="-1" width="12" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="L" id="hgE-7A-bez">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<accessibility description="Pan left"/>
|
||||
</textField>
|
||||
<textField toolTip="Pan" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1lZ-hX-6Kl">
|
||||
<rect key="frame" x="228" y="-1" width="12" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="R" id="lzr-NO-0Na">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
<accessibility description="Pan right"/>
|
||||
</textField>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="81" y="-111"/>
|
||||
<point key="canvasLocation" x="117.5" y="-117.5"/>
|
||||
</customView>
|
||||
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" hidesOnDeactivate="YES" oneShot="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="Cf4-3V-gl1" customClass="NSPanel">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" utility="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" topStrut="YES"/>
|
||||
<rect key="contentRect" x="248" y="350" width="980" height="335"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="778"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
|
||||
<view key="contentView" id="HlB-hX-Y0Y">
|
||||
<rect key="frame" x="0.0" y="0.0" width="980" height="335"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
@@ -170,7 +208,7 @@
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<clipView key="contentView" ambiguous="YES" id="Cdb-RA-YK0">
|
||||
<rect key="frame" x="1" y="1" width="565" height="243"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textView ambiguous="YES" editable="NO" importsGraphics="NO" richText="NO" id="LSG-PF-cl8">
|
||||
<rect key="frame" x="-4" y="0.0" width="572" height="243"/>
|
||||
@@ -191,14 +229,14 @@
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="qCC-lY-zQ6">
|
||||
<rect key="frame" x="-15" y="1" width="16" height="0.0"/>
|
||||
<rect key="frame" x="550" y="1" width="16" height="243"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6qu-yI-r00">
|
||||
<rect key="frame" x="391" y="20" width="203" height="11"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="The AirPlay Logo is a trademark of Apple Inc." id="lx7-k3-q16">
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="The AirPlay Logo is a trademark of Apple Inc." id="lx7-k3-q16">
|
||||
<font key="font" metaFont="miniSystem"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
@@ -218,10 +256,61 @@
|
||||
<color key="textColor" red="0.11543657067200695" green="0.4338699494949495" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<color key="backgroundColor" red="0.99215692281723022" green="0.9960784912109375" blue="0.9960784912109375" alpha="1" colorSpace="deviceRGB"/>
|
||||
</textFieldCell>
|
||||
<point key="canvasLocation" x="101.5" y="496"/>
|
||||
<point key="canvasLocation" x="-559" y="-118"/>
|
||||
</textField>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="F928CF85-B22A-4634-8160-BC84F45043E3" width="1" height="1">
|
||||
<mutableData key="keyedArchiveRepresentation">
|
||||
YnBsaXN0MDDUAQIDBAUGPT5YJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK4HCBMU
|
||||
GR4fIyQrLjE3OlUkbnVsbNUJCgsMDQ4PEBESVk5TU2l6ZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVw
|
||||
c1dOU0NvbG9ygAKADRIgwwAAgAOAC1Z7MSwgMX3SFQoWGFpOUy5vYmplY3RzoReABIAK0hUKGh2iGxyA
|
||||
BYAGgAkQANIgCiEiXxAUTlNUSUZGUmVwcmVzZW50YXRpb26AB4AITxEIrE1NACoAAAAKAAAADgEAAAMA
|
||||
AAABAAEAAAEBAAMAAAABAAEAAAECAAMAAAACAAgACAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAERAAQA
|
||||
AAABAAAACAESAAMAAAABAAEAAAEVAAMAAAABAAIAAAEWAAMAAAABAAEAAAEXAAQAAAABAAAAAgEcAAMA
|
||||
AAABAAEAAAFSAAMAAAABAAEAAAFTAAMAAAACAAEAAYdzAAcAAAf0AAAAuAAAAAAAAAf0YXBwbAIgAABt
|
||||
bnRyR1JBWVhZWiAH0AACAA4ADAAAAABhY3NwQVBQTAAAAABub25lAAAAAAAAAAAAAAAAAAAAAAAA9tYA
|
||||
AQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVk
|
||||
ZXNjAAAAwAAAAG9kc2NtAAABMAAABmZjcHJ0AAAHmAAAADh3dHB0AAAH0AAAABRrVFJDAAAH5AAAAA5k
|
||||
ZXNjAAAAAAAAABVHZW5lcmljIEdyYXkgUHJvZmlsZQAAAAAAAAAAAAAAFUdlbmVyaWMgR3JheSBQcm9m
|
||||
aWxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAA
|
||||
AAAfAAAADHNrU0sAAAAqAAABhGVuVVMAAAAoAAABrmNhRVMAAAAsAAAB1nZpVk4AAAAsAAACAnB0QlIA
|
||||
AAAqAAACLnVrVUEAAAAsAAACWGZyRlUAAAAqAAAChGh1SFUAAAAuAAACrnpoVFcAAAAQAAAC3G5iTk8A
|
||||
AAAsAAAC7GtvS1IAAAAYAAADGGNzQ1oAAAAkAAADMGhlSUwAAAAgAAADVHJvUk8AAAAkAAADdGRlREUA
|
||||
AAA6AAADmGl0SVQAAAAuAAAD0nN2U0UAAAAuAAAEAHpoQ04AAAAQAAAELmphSlAAAAAWAAAEPmVsR1IA
|
||||
AAAkAAAEVHB0UE8AAAA4AAAEeG5sTkwAAAAqAAAEsGVzRVMAAAAoAAAE2nRoVEgAAAAkAAAFAnRyVFIA
|
||||
AAAiAAAFJmZpRkkAAAAsAAAFSGhySFIAAAA6AAAFdHBsUEwAAAA2AAAFrnJ1UlUAAAAmAAAF5GFyRUcA
|
||||
AAAoAAAGCmRhREsAAAA0AAAGMgBWAWEAZQBvAGIAZQBjAG4A/QAgAHMAaQB2AP0AIABwAHIAbwBmAGkA
|
||||
bABHAGUAbgBlAHIAaQBjACAARwByAGEAeQAgAFAAcgBvAGYAaQBsAGUAUABlAHIAZgBpAGwAIABkAGUA
|
||||
IABnAHIAaQBzACAAZwBlAG4A6AByAGkAYwBDHqUAdQAgAGgA7ABuAGgAIABNAOAAdQAgAHgA4QBtACAA
|
||||
QwBoAHUAbgBnAFAAZQByAGYAaQBsACAAQwBpAG4AegBhACAARwBlAG4A6QByAGkAYwBvBBcEMAQzBDAE
|
||||
OwRMBD0EOAQ5ACAEPwRABD4ERAQwBDkEOwAgAEcAcgBhAHkAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIA
|
||||
aQBxAHUAZQAgAGcAcgBpAHMAwQBsAHQAYQBsAOEAbgBvAHMAIABzAHoA/AByAGsAZQAgAHAAcgBvAGYA
|
||||
aQBskBp1KHBwlo6Ccl9pY8+P8ABHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QB0AG8AbgBlAHAAcgBvAGYA
|
||||
aQBsx3y8GAAgAEcAcgBhAHkAINUEuFzTDMd8AE8AYgBlAGMAbgD9ACABYQBlAGQA/QAgAHAAcgBvAGYA
|
||||
aQBsBeQF6AXVBeQF2QXcACAARwByAGEAeQAgBdsF3AXcBdkAUAByAG8AZgBpAGwAIABnAHIAaQAgAGcA
|
||||
ZQBuAGUAcgBpAGMAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBmAGUAbgAtAFAA
|
||||
cgBvAGYAaQBsAFAAcgBvAGYAaQBsAG8AIABnAHIAaQBnAGkAbwAgAGcAZQBuAGUAcgBpAGMAbwBHAGUA
|
||||
bgBlAHIAaQBzAGsAIABnAHIA5QBzAGsAYQBsAGUAcAByAG8AZgBpAGxmbpAacHBepmPPj/Blh072TgCC
|
||||
LDCwMOwwpDDXMO0w1TChMKQw6wOTA7UDvQO5A7oDzAAgA8ADwQO/A8YDrwO7ACADswO6A8EDuQBQAGUA
|
||||
cgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGMAaQBuAHoAZQBuAHQAbwBzAEEAbABnAGUA
|
||||
bQBlAGUAbgAgAGcAcgBpAGoAcwBwAHIAbwBmAGkAZQBsAFAAZQByAGYAaQBsACAAZwByAGkAcwAgAGcA
|
||||
ZQBuAOkAcgBpAGMAbw5CDhsOIw5EDh8OJQ5MDioONQ5ADhcOMg4XDjEOSA4nDkQOGwBHAGUAbgBlAGwA
|
||||
IABHAHIAaQAgAFAAcgBvAGYAaQBsAGkAWQBsAGUAaQBuAGUAbgAgAGgAYQByAG0AYQBhAHAAcgBvAGYA
|
||||
aQBpAGwAaQBHAGUAbgBlAHIAaQENAGsAaQAgAHAAcgBvAGYAaQBsACAAcwBpAHYAaQBoACAAdABvAG4A
|
||||
bwB2AGEAVQBuAGkAdwBlAHIAcwBhAGwAbgB5ACAAcAByAG8AZgBpAGwAIABzAHoAYQByAG8BWwBjAGkE
|
||||
HgQxBEkEOAQ5ACAEQQQ1BEAESwQ5ACAEPwRABD4ERAQ4BDsETAZFBkQGQQAgBioGOQYxBkoGQQAgAEcA
|
||||
cgBhAHkAIAYnBkQGOQYnBkUARwBlAG4AZQByAGUAbAAgAGcAcgDlAHQAbwBuAGUAYgBlAHMAawByAGkA
|
||||
dgBlAGwAcwBlAAB0ZXh0AAAAAENvcHlyaWdodCAyMDA3IEFwcGxlIEluYy4sIGFsbCByaWdodHMgcmVz
|
||||
ZXJ2ZWQuAFhZWiAAAAAAAADzUQABAAAAARbMY3VydgAAAAAAAAABAc0AANIlJicoWiRjbGFzc25hbWVY
|
||||
JGNsYXNzZXNfEBBOU0JpdG1hcEltYWdlUmVwoycpKlpOU0ltYWdlUmVwWE5TT2JqZWN00iUmLC1XTlNB
|
||||
cnJheaIsKtIlJi8wXk5TTXV0YWJsZUFycmF5oy8sKtMyMwo0NTZXTlNXaGl0ZVxOU0NvbG9yU3BhY2VE
|
||||
MCAwABADgAzSJSY4OVdOU0NvbG9yojgq0iUmOzxXTlNJbWFnZaI7Kl8QD05TS2V5ZWRBcmNoaXZlctE/
|
||||
QFRyb290gAEACAARABoAIwAtADIANwBGAEwAVwBeAGUAcgB5AIEAgwCFAIoAjACOAJUAmgClAKcAqQCr
|
||||
ALAAswC1ALcAuQC7AMAA1wDZANsJiwmQCZsJpAm3CbsJxgnPCdQJ3AnfCeQJ8wn3Cf4KBgoTChgKGgoc
|
||||
CiEKKQosCjEKOQo8Ck4KUQpWAAAAAAAAAgEAAAAAAAAAQQAAAAAAAAAAAAAAAAAAClg
|
||||
</mutableData>
|
||||
</image>
|
||||
<image name="FermataIcon" width="284" height="284"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Copyright © 2016 Josh Junon
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
// Portions copyright (C) 2013 Apple Inc. All Rights Reserved.
|
||||
//
|
||||
// Based largely on SA_Device.cpp from Apple's SimpleAudioDriver Plug-In sample code. Also uses a few sections from Apple's
|
||||
@@ -2093,11 +2094,14 @@ void BGM_Device::ApplyClientRelativeVolume(UInt32 inClientID, UInt32 inIOBufferF
|
||||
Float32 theRelativeVolume = mClients.GetClientRelativeVolumeRT(inClientID);
|
||||
|
||||
auto thePanPositionInt = mClients.GetClientPanPositionRT(inClientID);
|
||||
Float32 thePanPosition = ((Float32)thePanPositionInt)/100.0f;
|
||||
Float32 thePanPosition = static_cast<Float32>(thePanPositionInt) / 100.0f;
|
||||
|
||||
// TODO When we get around to supporting devices with more than two channels, it would be worth looking into
|
||||
// kAudioFormatProperty_PanningMatrix and kAudioFormatProperty_BalanceFade in AudioFormat.h.
|
||||
|
||||
// TODO precompute matrix coefficients w/ volume and do everything in one pass
|
||||
|
||||
// Apply balance w/ crossover to the frames in the buffer.
|
||||
// Apply balance w/ crossfeed to the frames in the buffer.
|
||||
// Expect samples interleaved, starting with left
|
||||
if (thePanPosition > 0.0f) {
|
||||
for (UInt32 i = 0; i < inIOBufferFrameSize * 2; i += 2) {
|
||||
@@ -2117,17 +2121,16 @@ void BGM_Device::ApplyClientRelativeVolume(UInt32 inClientID, UInt32 inIOBufferF
|
||||
}
|
||||
}
|
||||
|
||||
if(theRelativeVolume != 1.)
|
||||
if(theRelativeVolume != 1.0f)
|
||||
{
|
||||
for(UInt32 i = 0; i < inIOBufferFrameSize * 2; i++)
|
||||
{
|
||||
Float32 theAdjustedSample = theBuffer[i] * theRelativeVolume;
|
||||
|
||||
// Clamp to [-1.0, 1.0]
|
||||
// Clamp to [-1, 1].
|
||||
// (This way is roughly 6 times faster than using std::min and std::max because the compiler can vectorize the loop.)
|
||||
const Float32 theAdjustedSampleClippedBelow = theAdjustedSample < -1. ? -1. : theAdjustedSample;
|
||||
theBuffer[i] = theAdjustedSampleClippedBelow > 1. ? 1. : theAdjustedSampleClippedBelow;
|
||||
|
||||
const Float32 theAdjustedSampleClippedBelow = theAdjustedSample < -1.0f ? -1.0f : theAdjustedSample;
|
||||
theBuffer[i] = theAdjustedSampleClippedBelow > 1.0f ? 1.0f : theAdjustedSampleClippedBelow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2137,7 +2140,7 @@ bool BGM_Device::BufferIsAudible(UInt32 inIOBufferFrameSize, const void* inBuffe
|
||||
// Check each frame to see if any are audible
|
||||
for(UInt32 i = 0; i < inIOBufferFrameSize * 2; i++)
|
||||
{
|
||||
if (0. != reinterpret_cast<const Float32*>(inBuffer)[i]) {
|
||||
if (0.0f != reinterpret_cast<const Float32*>(inBuffer)[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
//
|
||||
|
||||
// Self Include
|
||||
@@ -374,7 +375,7 @@ bool BGM_ClientMap::SetClientsPanPosition(pid_t searchKey, SInt32 inPanPosition)
|
||||
CAMutex::Locker theShadowMapsLocker(mShadowMapsMutex);
|
||||
|
||||
auto theSetPansInShadowMapsFunc = [&] {
|
||||
// Look up the clients for the key and update their pan positions
|
||||
// Look up the clients for the key and update their pan positions
|
||||
auto theClients = GetClients(searchKey);
|
||||
if(theClients != nullptr) {
|
||||
for(auto theClient: *theClients) {
|
||||
|
||||
@@ -118,21 +118,24 @@ private:
|
||||
void CopyClientIntoAppVolumesArray(BGM_Client inClient, CAVolumeCurve inVolumeCurve, CACFArray& ioAppVolumes) const;
|
||||
|
||||
public:
|
||||
// Returns true if a client for PID inAppPID was found and its relative volume changed.
|
||||
bool SetClientsRelativeVolume(pid_t inAppPID, Float32 inRelativeVolume);
|
||||
// Returns true if a client for bundle ID inAppBundleID was found and its relative volume changed.
|
||||
bool SetClientsRelativeVolume(CACFString inAppBundleID, Float32 inRelativeVolume);
|
||||
|
||||
// Using the template function hits LLVM Bug 23987
|
||||
// TODO Switch to template function
|
||||
|
||||
// Returns true if a client for the key was found and its relative volume changed.
|
||||
//template <typename T>
|
||||
//bool SetClientsRelativeVolume(T _Null_unspecified key, Float32 inRelativeVolume);
|
||||
//bool SetClientsRelativeVolume(T _Null_unspecified searchKey, Float32 inRelativeVolume);
|
||||
//
|
||||
//template <typename T>
|
||||
//bool SetClientsPanPosition(T _Null_unspecified searchKey, SInt32 inPanPosition);
|
||||
|
||||
// Returns true if a client for PID inAppPID was found and its relative volume changed.
|
||||
bool SetClientsPanPosition(pid_t inAppPID, SInt32 inPanPosition);
|
||||
bool SetClientsRelativeVolume(pid_t inAppPID, Float32 inRelativeVolume);
|
||||
// Returns true if a client for bundle ID inAppBundleID was found and its relative volume changed.
|
||||
bool SetClientsRelativeVolume(CACFString inAppBundleID, Float32 inRelativeVolume);
|
||||
|
||||
// Returns true if a client for PID inAppPID was found and its pan position changed.
|
||||
bool SetClientsPanPosition(pid_t inAppPID, SInt32 inPanPosition);
|
||||
// Returns true if a client for bundle ID inAppBundleID was found and its pan position changed.
|
||||
bool SetClientsPanPosition(CACFString inAppBundleID, SInt32 inPanPosition);
|
||||
|
||||
void StartIONonRT(UInt32 inClientID) { UpdateClientIOStateNonRT(inClientID, true); }
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
// BGMDriver
|
||||
//
|
||||
// Copyright © 2016 Kyle Neideck
|
||||
// Copyright © 2017 Andrew Tonner
|
||||
//
|
||||
|
||||
// Self Include
|
||||
|
||||
@@ -110,8 +110,8 @@ enum
|
||||
// applied to kBGMAppVolumesKey_RelativeVolume when it's first set and then each of the app's samples are multiplied
|
||||
// by it.
|
||||
#define kBGMAppVolumesKey_RelativeVolume "rvol"
|
||||
// A CFNumber<SInt32> between kAppPanLeftRawValue and kAppPanRightRawValue. A negative value has a higher proportion of left channel,
|
||||
// and a positive value has a higher proportion of right channel.
|
||||
// A CFNumber<SInt32> between kAppPanLeftRawValue and kAppPanRightRawValue. A negative value has a higher proportion
|
||||
// of left channel, and a positive value has a higher proportion of right channel.
|
||||
#define kBGMAppVolumesKey_PanPosition "ppos"
|
||||
// The app's pid as a CFNumber. May be omitted if kBGMAppVolumesKey_BundleID is present.
|
||||
#define kBGMAppVolumesKey_ProcessID "pid"
|
||||
|
||||
Reference in New Issue
Block a user