Last active
September 28, 2024 04:37
-
-
Save bradhowes/b9784b1ba6c3d93a6fead12f8a3138a4 to your computer and use it in GitHub Desktop.
Swift playground that integrates a @published attribute and a AUParameter instance, allowing changes in either to affect the other.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import AVFoundation | |
import PlaygroundSupport | |
class Model: ObservableObject { | |
@Published var value: Double = 5.0 // sole source of truth | |
} | |
class ParamTree { | |
static let address: AUParameterAddress = 123 | |
let parameter: AUParameter | |
let parameterTree: AUParameterTree | |
init(model: Model) { | |
parameter = AUParameterTree.createParameter(withIdentifier: "parameter", name: "Parameter", | |
address: Self.address, min: 0.0, max: 10.0, | |
unit: .generic, unitName: nil, | |
flags: [.flag_IsReadable, .flag_IsWritable], | |
valueStrings: nil, dependentParameters: nil) | |
parameter.value = AUValue(model.value) | |
parameterTree = AUParameterTree.createTree(withChildren: [parameter]) | |
// Set closure to convert AUParameter values into String | |
parameterTree.implementorStringFromValueCallback = { param, value in | |
guard param.address == Self.address, let value = value else { return "?" } | |
return String(format: "%.2f", value.pointee) | |
} | |
// Set closure to change model value via an AUParameter | |
parameterTree.implementorValueObserver = { param, value in | |
guard param.address == Self.address else { return } | |
print("set parameter: \(value)") | |
model.value = Double(value) | |
} | |
// Set closure to provide values for an AUParameter | |
parameterTree.implementorValueProvider = { param in | |
guard param.address == Self.address else { return 0.0 } | |
print("get parameter: \(model.value)") | |
return AUValue(model.value) | |
} | |
} | |
} | |
extension AUParameter { | |
/// Obtain a ClosedRange using the `minValue` and `maxValue` attributes | |
var bounds: ClosedRange<AUValue> { minValue...maxValue } | |
} | |
extension Comparable { | |
/** | |
Force our value to be within the given closed range | |
- parameter range: the limits to apply | |
- returns: clamped value | |
*/ | |
func clamped(to range: ClosedRange<Self>) -> Self { min(max(self, range.lowerBound), range.upperBound) } | |
} | |
struct ValueView: View { | |
@Binding var value: Double | |
var body: some View { | |
Text("Value: \(value)") | |
} | |
} | |
struct ContentView: View { | |
@ObservedObject var model: Model | |
let params: ParamTree | |
init(model: Model) { | |
self.model = model | |
self.params = ParamTree(model: model) | |
} | |
var body: some View { | |
VStack { | |
Text("Hello World") | |
ValueView(value: $model.value) | |
// Manipulate the model value | |
Slider(value: $model.value, in: Double(params.parameter.minValue)...Double(params.parameter.maxValue)) | |
// Decrease the AU parameter by 1 | |
Button("Down") { | |
guard let parameter = params.parameterTree.parameter(withAddress: 123) else { return } | |
print("Dn - parameter: \(parameter.value)") | |
print("Dn - model: \(model.value)") | |
let value = AUValue(parameter.value - 1.0).clamped(to: parameter.bounds) | |
parameter.setValue(value, originator: nil) | |
print("Dn - parameter: \(parameter.value)") | |
print("Dn - model: \(model.value)") | |
} | |
// Increase the AU parameter by 1 | |
Button("Up") { | |
guard let parameter = params.parameterTree.parameter(withAddress: 123) else { return } | |
print("Up - parameter: \(parameter.value)") | |
print("Up - model: \(model.value)") | |
let value = AUValue(parameter.value + 1.0).clamped(to: parameter.bounds) | |
parameter.setValue(value, originator: nil) | |
print("Up - parameter: \(parameter.value)") | |
print("Up - model: \(model.value)") | |
} | |
} | |
} | |
} | |
let view = ContentView(model: Model()) | |
PlaygroundPage.current.setLiveView(view) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment