fixes mapping changes

This commit is contained in:
André Michelle
2026-03-20 12:59:35 +01:00
parent 72a5b51278
commit 975d91918a
5 changed files with 68 additions and 94 deletions
@@ -20,6 +20,7 @@ export type ScriptCompilerConfig = {
}
const COMPILER_VERSION = 1
const FLOAT_TOLERANCE = 1e-6
const createHeaderPattern = (tag: string): RegExp => new RegExp(`^// @${tag} (\\w+) (\\d+) (\\d+)\n`)
@@ -57,9 +58,13 @@ const reconcileParameters = (deviceBox: ScriptDeviceBox, declared: ReadonlyArray
const existing = existingByLabel.get(declaration.label)
const mappedDefault = declaration.defaultValue
if (isDefined(existing)) {
existing.index.setValue(unifiedIndex)
existing.defaultValue.setValue(mappedDefault)
existing.value.setValue(mappedDefault)
if (existing.index.getValue() !== unifiedIndex) {
existing.index.setValue(unifiedIndex)
}
if (Math.abs(existing.defaultValue.getValue() - mappedDefault) > FLOAT_TOLERANCE) {
existing.defaultValue.setValue(mappedDefault)
existing.value.setValue(mappedDefault)
}
} else {
WerkstattParameterBox.create(boxGraph, UUID.generate(), paramBox => {
paramBox.owner.refer(deviceBox.parameters)
@@ -1,4 +1,7 @@
import {isDefined, Nullable, StringMapping, ValueMapping} from "@opendaw/lib-std"
import {asInstanceOf, isDefined, Nullable, ObservableValue, Observer, StringMapping, Subscription, TerminableOwner, ValueMapping} from "@opendaw/lib-std"
import {PointerListener, PointerTypes} from "@opendaw/lib-box"
import {WerkstattParameterBox} from "@opendaw/studio-boxes"
import {ParameterAdapterSet} from "./ParameterAdapterSet"
export type ParamMapping = "unipolar" | "linear" | "exp" | "int" | "bool"
@@ -163,3 +166,47 @@ export const resolveParamMappings = (declaration: ParamDeclaration): {
valueMapping: resolveValueMapping(declaration),
stringMapping: resolveStringMapping(declaration)
})
const declarationEquals = (a: ParamDeclaration, b: ParamDeclaration): boolean =>
a.mapping === b.mapping && a.min === b.min && a.max === b.max && a.unit === b.unit
export const subscribeScriptParams = (
parametric: ParameterAdapterSet,
codeField: {getValue(): string, subscribe(observer: Observer<ObservableValue<string>>): Subscription},
parametersHub: {pointerHub: {catchupAndSubscribe(listener: PointerListener, ...filter: ReadonlyArray<PointerTypes>): Subscription}},
terminator: TerminableOwner
): void => {
const cachedDeclarations = new Map<string, ParamDeclaration>()
terminator.own(
parametersHub.pointerHub.catchupAndSubscribe({
onAdded: (({box: parameterBox}) => {
const paramBox = asInstanceOf(parameterBox, WerkstattParameterBox)
const label = paramBox.label.getValue()
const declarations = parseParams(codeField.getValue())
const declaration = declarations.find(decl => decl.label === label)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {valueMapping: ValueMapping.unipolar(), stringMapping: StringMapping.percent({fractionDigits: 1})}
parametric.createParameter(paramBox.value, valueMapping, stringMapping, label)
if (isDefined(declaration)) {cachedDeclarations.set(label, declaration)}
}),
onRemoved: (({box}) => {
const paramBox = asInstanceOf(box, WerkstattParameterBox)
cachedDeclarations.delete(paramBox.label.getValue())
parametric.removeParameter(paramBox.value.address)
})
})
)
terminator.own(codeField.subscribe(() => {
const declarations = parseParams(codeField.getValue())
for (const adapter of parametric.parameters()) {
const newDeclaration = declarations.find(decl => decl.label === adapter.name)
if (!isDefined(newDeclaration)) {continue}
const oldDeclaration = cachedDeclarations.get(adapter.name)
if (isDefined(oldDeclaration) && declarationEquals(oldDeclaration, newDeclaration)) {continue}
const {valueMapping, stringMapping} = resolveParamMappings(newDeclaration)
adapter.updateMappings(valueMapping, stringMapping)
cachedDeclarations.set(adapter.name, newDeclaration)
}
}))
}
@@ -1,6 +1,6 @@
import {asInstanceOf, isDefined, Option, StringMapping, Terminator, UUID, ValueMapping} from "@opendaw/lib-std"
import {Option, Terminator, UUID} from "@opendaw/lib-std"
import {Address, BooleanField, Int32Field, PointerField, StringField} from "@opendaw/lib-box"
import {WerkstattDeviceBox, WerkstattParameterBox} from "@opendaw/studio-boxes"
import {WerkstattDeviceBox} from "@opendaw/studio-boxes"
import {Pointers} from "@opendaw/studio-enums"
import {AudioEffectDeviceAdapter, DeviceHost, Devices} from "../../DeviceAdapter"
import {LabeledAudioOutput} from "../../LabeledAudioOutputsOwner"
@@ -8,7 +8,7 @@ import {BoxAdaptersContext} from "../../BoxAdaptersContext"
import {DeviceManualUrls} from "../../DeviceManualUrls"
import {AudioUnitBoxAdapter} from "../../audio-unit/AudioUnitBoxAdapter"
import {ParameterAdapterSet} from "../../ParameterAdapterSet"
import {parseParams, resolveParamMappings} from "../../ScriptParamDeclaration"
import {subscribeScriptParams} from "../../ScriptParamDeclaration"
export class WerkstattDeviceBoxAdapter implements AudioEffectDeviceAdapter {
readonly #terminator = new Terminator()
@@ -25,32 +25,7 @@ export class WerkstattDeviceBoxAdapter implements AudioEffectDeviceAdapter {
this.#context = context
this.#box = box
this.#parametric = this.#terminator.own(new ParameterAdapterSet(this.#context))
this.#terminator.own(
box.parameters.pointerHub.catchupAndSubscribe({
onAdded: (({box: parameterBox}) => {
const paramBox = asInstanceOf(parameterBox, WerkstattParameterBox)
const label = paramBox.label.getValue()
const declarations = parseParams(box.code.getValue())
const declaration = declarations.find(decl => decl.label === label)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {valueMapping: ValueMapping.unipolar(), stringMapping: StringMapping.percent({fractionDigits: 1})}
this.#parametric.createParameter(paramBox.value, valueMapping, stringMapping, label)
}),
onRemoved: (({box}) => this.#parametric
.removeParameter(asInstanceOf(box, WerkstattParameterBox).value.address))
})
)
this.#terminator.own(box.code.subscribe(() => {
const declarations = parseParams(box.code.getValue())
for (const adapter of this.#parametric.parameters()) {
const declaration = declarations.find(decl => decl.label === adapter.name)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {valueMapping: ValueMapping.unipolar(), stringMapping: StringMapping.percent({fractionDigits: 1})}
adapter.updateMappings(valueMapping, stringMapping)
}
}))
subscribeScriptParams(this.#parametric, box.code, box.parameters, this.#terminator)
}
get box(): WerkstattDeviceBox {return this.#box}
@@ -1,6 +1,6 @@
import {asInstanceOf, isDefined, Option, StringMapping, Terminator, UUID, ValueMapping} from "@opendaw/lib-std"
import {Option, Terminator, UUID} from "@opendaw/lib-std"
import {Address, BooleanField, StringField} from "@opendaw/lib-box"
import {ApparatDeviceBox, WerkstattParameterBox} from "@opendaw/studio-boxes"
import {ApparatDeviceBox} from "@opendaw/studio-boxes"
import {DeviceHost, Devices, InstrumentDeviceBoxAdapter} from "../../DeviceAdapter"
import {LabeledAudioOutput} from "../../LabeledAudioOutputsOwner"
import {BoxAdaptersContext} from "../../BoxAdaptersContext"
@@ -8,7 +8,7 @@ import {DeviceManualUrls} from "../../DeviceManualUrls"
import {ParameterAdapterSet} from "../../ParameterAdapterSet"
import {TrackType} from "../../timeline/TrackType"
import {AudioUnitBoxAdapter} from "../../audio-unit/AudioUnitBoxAdapter"
import {parseParams, resolveParamMappings} from "../../ScriptParamDeclaration"
import {subscribeScriptParams} from "../../ScriptParamDeclaration"
export class ApparatDeviceBoxAdapter implements InstrumentDeviceBoxAdapter {
readonly #terminator = new Terminator()
@@ -25,35 +25,7 @@ export class ApparatDeviceBoxAdapter implements InstrumentDeviceBoxAdapter {
this.#context = context
this.#box = box
this.#parametric = this.#terminator.own(new ParameterAdapterSet(this.#context))
this.#terminator.own(
box.parameters.pointerHub.catchupAndSubscribe({
onAdded: (({box: parameterBox}) => {
const paramBox = asInstanceOf(parameterBox, WerkstattParameterBox)
const label = paramBox.label.getValue()
const declarations = parseParams(box.code.getValue())
const declaration = declarations.find(decl => decl.label === label)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {
valueMapping: ValueMapping.unipolar(),
stringMapping: StringMapping.percent({fractionDigits: 1})
}
this.#parametric.createParameter(paramBox.value, valueMapping, stringMapping, label)
}),
onRemoved: (({box}) => this.#parametric
.removeParameter(asInstanceOf(box, WerkstattParameterBox).value.address))
})
)
this.#terminator.own(box.code.subscribe(() => {
const declarations = parseParams(box.code.getValue())
for (const adapter of this.#parametric.parameters()) {
const declaration = declarations.find(decl => decl.label === adapter.name)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {valueMapping: ValueMapping.unipolar(), stringMapping: StringMapping.percent({fractionDigits: 1})}
adapter.updateMappings(valueMapping, stringMapping)
}
}))
subscribeScriptParams(this.#parametric, box.code, box.parameters, this.#terminator)
}
get box(): ApparatDeviceBox {return this.#box}
@@ -1,13 +1,13 @@
import {asInstanceOf, isDefined, StringMapping, Terminator, UUID, ValueMapping} from "@opendaw/lib-std"
import {Option, Terminator, UUID} from "@opendaw/lib-std"
import {Address, BooleanField, Int32Field, PointerField, StringField} from "@opendaw/lib-box"
import {SpielwerkDeviceBox, WerkstattParameterBox} from "@opendaw/studio-boxes"
import {SpielwerkDeviceBox} from "@opendaw/studio-boxes"
import {Pointers} from "@opendaw/studio-enums"
import {DeviceHost, Devices, MidiEffectDeviceAdapter} from "../../DeviceAdapter"
import {BoxAdaptersContext} from "../../BoxAdaptersContext"
import {DeviceManualUrls} from "../../DeviceManualUrls"
import {AudioUnitBoxAdapter} from "../../audio-unit/AudioUnitBoxAdapter"
import {ParameterAdapterSet} from "../../ParameterAdapterSet"
import {parseParams, resolveParamMappings} from "../../ScriptParamDeclaration"
import {subscribeScriptParams} from "../../ScriptParamDeclaration"
export class SpielwerkDeviceBoxAdapter implements MidiEffectDeviceAdapter {
readonly #terminator = new Terminator()
@@ -24,32 +24,7 @@ export class SpielwerkDeviceBoxAdapter implements MidiEffectDeviceAdapter {
this.#context = context
this.#box = box
this.#parametric = this.#terminator.own(new ParameterAdapterSet(this.#context))
this.#terminator.own(
box.parameters.pointerHub.catchupAndSubscribe({
onAdded: (({box: parameterBox}) => {
const paramBox = asInstanceOf(parameterBox, WerkstattParameterBox)
const label = paramBox.label.getValue()
const declarations = parseParams(box.code.getValue())
const declaration = declarations.find(decl => decl.label === label)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {valueMapping: ValueMapping.unipolar(), stringMapping: StringMapping.percent({fractionDigits: 1})}
this.#parametric.createParameter(paramBox.value, valueMapping, stringMapping, label)
}),
onRemoved: (({box}) => this.#parametric
.removeParameter(asInstanceOf(box, WerkstattParameterBox).value.address))
})
)
this.#terminator.own(box.code.subscribe(() => {
const declarations = parseParams(box.code.getValue())
for (const adapter of this.#parametric.parameters()) {
const declaration = declarations.find(decl => decl.label === adapter.name)
const {valueMapping, stringMapping} = isDefined(declaration)
? resolveParamMappings(declaration)
: {valueMapping: ValueMapping.unipolar(), stringMapping: StringMapping.percent({fractionDigits: 1})}
adapter.updateMappings(valueMapping, stringMapping)
}
}))
subscribeScriptParams(this.#parametric, box.code, box.parameters, this.#terminator)
}
get box(): SpielwerkDeviceBox {return this.#box}