Merge pull request #486 from FoolHen/midi-unit-range

Add units to MIDI range control
This commit is contained in:
Robin Davies
2026-06-02 00:58:41 -04:00
committed by GitHub
2 changed files with 66 additions and 9 deletions
+64 -9
View File
@@ -25,7 +25,7 @@ import { withStyles } from "tss-react/mui";
import { createStyles } from './WithStyles';
import Snackbar from '@mui/material/Snackbar';
import { UiPlugin } from './Lv2Plugin';
import { UiPlugin, UiControl } from './Lv2Plugin';
import MenuItem from '@mui/material/MenuItem';
import Select from '@mui/material/Select';
@@ -96,6 +96,7 @@ interface MidiBindingViewProps extends WithStyles<typeof styles> {
midiBinding: MidiBinding;
midiControlType: MidiControlType;
canDoTapTempo: boolean;
uiControl?: UiControl;
onChange: (instanceId: number, newBinding: MidiBinding) => void;
}
@@ -189,14 +190,53 @@ const MidiBindingView =
}
handleMinChange(value: number): void {
let newBinding = this.props.midiBinding.clone();
newBinding.minValue = value;
newBinding.minValue = this.realToMidi(value);
this.props.onChange(this.props.instanceId, newBinding);
}
handleMaxChange(value: number): void {
let newBinding = this.props.midiBinding.clone();
newBinding.maxValue = value;
newBinding.maxValue = this.realToMidi(value);
this.props.onChange(this.props.instanceId, newBinding);
}
private realToMidi(realValue: number): number {
let control = this.props.uiControl;
if (!control) return realValue;
let range = control.max_value - control.min_value;
if (range === 0) return 0;
return (realValue - control.min_value) / range;
}
private midiToReal(midiValue: number): number {
let control = this.props.uiControl;
if (!control) return midiValue;
return midiValue * (control.max_value - control.min_value) + control.min_value;
}
private getDisplayUnit(): string {
let control = this.props.uiControl;
if (!control) return "";
if (control.custom_units !== "") {
return control.custom_units.replace("%f", "");
}
switch (control.units) {
case "bar": return " bar";
case "beat": return " beats";
case "bpm": return " bpm";
case "cent": return " cents";
case "cm": return " cm";
case "db": return " dB";
case "hz": return " Hz";
case "khz": return " kHz";
case "km": return " km";
case "m": return " m";
case "mhz": return " MHz";
case "midiNote": return "MIDI note";
case "min": return " min";
case "ms": return " ms";
case "pc": return " %";
case "s": return " s";
case "semitone12TET": return " st";
default: return "";
}
}
handleCtlMinChange(value: number): void {
let newBinding = this.props.midiBinding.clone();
newBinding.minControlValue = Math.round(value);
@@ -638,21 +678,36 @@ const MidiBindingView =
)
}
{
showLinearRange && (
showLinearRange && (() => {
let uiControl = this.props.uiControl;
let displayMin = uiControl ? uiControl.min_value : 0;
let displayMax = uiControl ? uiControl.max_value : 1;
let unit = this.getDisplayUnit();
let isInteger = uiControl?.integer_property ?? false;
return (
<div style={{ display: "flex", flexFlow: "row wrap", alignItems: "center" }}>
<div className={classes.controlDiv}>
<Typography noWrap display="inline">Min Val:&nbsp;</Typography>
<NumericInput value={midiBinding.minValue} ariaLabel='min'
min={0} max={1} onChange={(value) => { this.handleMinChange(value); }}
<NumericInput value={this.midiToReal(midiBinding.minValue)} ariaLabel='min'
min={displayMin} max={displayMax} integer={isInteger}
onChange={(value) => { this.handleMinChange(value); }}
/>
{unit !== "" && (
<Typography noWrap display="inline">&nbsp;{unit.trim()}</Typography>
)}
</div>
<div className={classes.controlDiv}>
<Typography noWrap display="inline">Max Val:&nbsp;</Typography>
<NumericInput value={midiBinding.maxValue} ariaLabel='max'
min={0} max={1} onChange={(value) => { this.handleMaxChange(value); }} />
<NumericInput value={this.midiToReal(midiBinding.maxValue)} ariaLabel='max'
min={displayMin} max={displayMax} integer={isInteger}
onChange={(value) => { this.handleMaxChange(value); }} />
{unit !== "" && (
<Typography noWrap display="inline">&nbsp;{unit.trim()}</Typography>
)}
</div>
</div>
)
);
})()
}
{
canRotaryScale && (
+2
View File
@@ -214,6 +214,7 @@ export const MidiBindingDialog =
midiControlType={ getMidiControlType(plugin, "__bypass")
}
canDoTapTempo={false }
uiControl={plugin.getControl("__bypass")}
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
/>
</td>
@@ -258,6 +259,7 @@ export const MidiBindingDialog =
midiControlType={getMidiControlType(plugin, symbol)}
midiBinding={item.getMidiBinding(symbol)}
canDoTapTempo={canDoTapTempo(plugin, symbol)}
uiControl={control}
onChange={(instanceId: number, newItem: MidiBinding) => this.handleItemChanged(instanceId, newItem)}
/>
</td>