mirror of
https://github.com/Toxblh/MTMR.git
synced 2026-01-11 09:28:38 +00:00
Rewrote presets parsing. Instead of parsing presets in a separate file using bunch of huge enums it is now parsed inside each object. To implement a new class: 1. Derive your class from CustomTouchBarItem (for static) or CustomButtonTouchBarItem (for buttons) 2. Override class var typeIdentifier with your object identificator 3. Override init(from decoder: Decoder) and read all custom json params you need 4. Don't forget to call super.init(identifier: CustomTouchBarItem.createIdentifier(type)) in the init() function 5. Add your new class to BarItemDefinition.types in ItemParsing.swift Good example is PomodoroBarItem If you want to inherid from some other NS class (NSSlider or NSPopoverTouchBarItem or other) then look into GroupBarItem and BrightnessViewController
125 lines
4.8 KiB
Swift
125 lines
4.8 KiB
Swift
import AppKit
|
|
import AVFoundation
|
|
import Cocoa
|
|
import CoreAudio
|
|
|
|
class VolumeViewController: CustomTouchBarItem {
|
|
private(set) var sliderItem: CustomSlider!
|
|
|
|
override class var typeIdentifier: String {
|
|
return "volume"
|
|
}
|
|
|
|
private enum CodingKeys: String, CodingKey {
|
|
case image
|
|
}
|
|
|
|
init(identifier: NSTouchBarItem.Identifier, image: NSImage? = nil) {
|
|
super.init(identifier: identifier)
|
|
|
|
self.setup(image: image)
|
|
}
|
|
|
|
required init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
let image = try container.decodeIfPresent(Source.self, forKey: .image)?.image
|
|
|
|
try super.init(from: decoder)
|
|
|
|
self.setup(image: image)
|
|
}
|
|
|
|
func setup(image: NSImage?) {
|
|
var forPropertyAddress = AudioObjectPropertyAddress(
|
|
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
|
mScope: kAudioDevicePropertyScopeOutput,
|
|
mElement: kAudioObjectPropertyElementMaster
|
|
)
|
|
|
|
AudioObjectAddPropertyListenerBlock(defaultDeviceID, &forPropertyAddress, nil, audioObjectPropertyListenerBlock)
|
|
|
|
if image == nil {
|
|
sliderItem = CustomSlider()
|
|
} else {
|
|
sliderItem = CustomSlider(knob: image!)
|
|
}
|
|
sliderItem.target = self
|
|
sliderItem.action = #selector(VolumeViewController.sliderValueChanged(_:))
|
|
sliderItem.minValue = 0.0
|
|
sliderItem.maxValue = 100.0
|
|
sliderItem.floatValue = getInputGain() * 100
|
|
|
|
view = sliderItem
|
|
}
|
|
|
|
func audioObjectPropertyListenerBlock(numberAddresses _: UInt32, addresses _: UnsafePointer<AudioObjectPropertyAddress>) {
|
|
DispatchQueue.main.async {
|
|
self.sliderItem.floatValue = self.getInputGain() * 100
|
|
}
|
|
}
|
|
|
|
|
|
required init?(coder _: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
deinit {
|
|
sliderItem.unbind(NSBindingName.value)
|
|
}
|
|
|
|
@objc func sliderValueChanged(_ sender: Any) {
|
|
if let sliderItem = sender as? NSSlider {
|
|
_ = setInputGain(Float32(sliderItem.intValue) / 100.0)
|
|
}
|
|
}
|
|
|
|
private var defaultDeviceID: AudioObjectID {
|
|
var deviceID: AudioObjectID = AudioObjectID(0)
|
|
var size: UInt32 = UInt32(MemoryLayout<AudioObjectID>.size)
|
|
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
|
address.mSelector = AudioObjectPropertySelector(kAudioHardwarePropertyDefaultOutputDevice)
|
|
address.mScope = AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal)
|
|
address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)
|
|
AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &size, &deviceID)
|
|
return deviceID
|
|
}
|
|
|
|
private func getInputGain() -> Float32 {
|
|
var volume: Float32 = 0.5
|
|
var size: UInt32 = UInt32(MemoryLayout.size(ofValue: volume))
|
|
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
|
address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume)
|
|
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
|
|
address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)
|
|
AudioObjectGetPropertyData(defaultDeviceID, &address, 0, nil, &size, &volume)
|
|
return volume
|
|
}
|
|
|
|
private func setInputGain(_ volume: Float32) -> OSStatus {
|
|
var inputVolume: Float32 = volume
|
|
|
|
if inputVolume == 0.0 {
|
|
_ = setMute(mute: 1)
|
|
} else {
|
|
_ = setMute(mute: 0)
|
|
}
|
|
|
|
let size: UInt32 = UInt32(MemoryLayout.size(ofValue: inputVolume))
|
|
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
|
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
|
|
address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)
|
|
address.mSelector = AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume)
|
|
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &inputVolume)
|
|
}
|
|
|
|
private func setMute(mute: Int) -> OSStatus {
|
|
var muteVal: Int = mute
|
|
var address: AudioObjectPropertyAddress = AudioObjectPropertyAddress()
|
|
address.mSelector = AudioObjectPropertySelector(kAudioDevicePropertyMute)
|
|
let size: UInt32 = UInt32(MemoryLayout.size(ofValue: muteVal))
|
|
address.mScope = AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput)
|
|
address.mElement = AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)
|
|
return AudioObjectSetPropertyData(defaultDeviceID, &address, 0, nil, size, &muteVal)
|
|
}
|
|
}
|