Update sidechain references after topology change.

This commit is contained in:
Robin E. R. Davies
2025-09-30 21:25:08 -04:00
parent 25494d6f3c
commit aa26fb2fea
3 changed files with 101 additions and 12 deletions
+35
View File
@@ -394,6 +394,7 @@ export class Pedalboard implements Deserializable<Pedalboard> {
pathProperties: {[Name: string]: string} = {};
selectedPlugin: number = -1;
// yields all items in the pedalboard, including split items. Splits are yielded before their children.
*itemsGenerator(): Generator<PedalboardItem, void, undefined> {
let it = itemGenerator_(this.items);
while (true)
@@ -403,6 +404,16 @@ export class Pedalboard implements Deserializable<Pedalboard> {
yield v.value;
}
}
// same as itemsGenerator, but yields split items after their chains.
*itemsGeneratorSplitAfter(): Generator<PedalboardItem, void, undefined> {
let it = itemGeneratorSplitAfter_(this.items);
while (true)
{
let v = it.next();
if (v.done) break;
yield v.value;
}
}
makeSnapshot(): Snapshot {
let result = new Snapshot();
@@ -793,4 +804,28 @@ function* itemGenerator_(items: PedalboardItem[]): Generator<PedalboardItem, voi
}
}
function* itemGeneratorSplitAfter_(items: PedalboardItem[]): Generator<PedalboardItem, void, undefined> {
for (let i = 0; i < items.length; ++i) {
let item = items[i];
if (item.uri === SPLIT_PEDALBOARD_ITEM_URI) {
let splitItem = item as PedalboardSplitItem;
let it = itemGenerator_(splitItem.topChain);
while (true) {
let v = it.next();
if (v.done) break;
yield v.value;
}
it = itemGenerator_(splitItem.bottomChain);
while (true) {
let v = it.next();
if (v.done) break;
yield v.value;
}
}
yield item;
}
}
+55 -6
View File
@@ -659,6 +659,7 @@ export class PiPedalModel //implements PiPedalModel
}
private setModelPedalboard(pedalboard: Pedalboard) {
this.removeInvalidSidechains(pedalboard);
this.pedalboard.set(pedalboard);
this.selectedSnapshot.set(pedalboard.selectedSnapshot);
this.updateEnabledItems(pedalboard);
@@ -1763,13 +1764,17 @@ export class PiPedalModel //implements PiPedalModel
}
let it = newPedalboard.itemsGenerator();
let oldInstanceId = -1;
let newInstanceId = -1;
while (true) {
let v = it.next();
if (v.done) break;
let item = v.value;
if (item.instanceId === itemId) {
oldInstanceId = item.instanceId;
item.deserialize(new PedalboardItem()); // skeezy way to re-initialize.
item.instanceId = ++newPedalboard.nextInstanceId;
newInstanceId = item.instanceId;
item.uri = selectedUri;
item.pluginName = plugin.name;
item.controlValues = this.getDefaultValues(item.uri);
@@ -1784,6 +1789,9 @@ export class PiPedalModel //implements PiPedalModel
item.pathProperties[fileProperty.patchProperty] = "null";
}
newPedalboard.selectedPlugin = item.instanceId;
if (oldInstanceId !== -1) {
this.updateSidechainReferences(newPedalboard, oldInstanceId, newInstanceId);
}
this.setModelPedalboard(newPedalboard);
this.updateServerPedalboard()
return item.instanceId;
@@ -1938,6 +1946,9 @@ export class PiPedalModel //implements PiPedalModel
newPedalboard.replaceItem(fromInstanceId, emptyItem);
newPedalboard.replaceItem(toInstanceId, fromItem);
newPedalboard.selectedPlugin = fromItem.instanceId;
if (!toItem.isEmpty()) {
this.updateSidechainReferences(newPedalboard, toItem.instanceId, fromItem.instanceId);
}
this.setModelPedalboard(newPedalboard);
this.updateServerPedalboard();
@@ -3545,29 +3556,67 @@ export class PiPedalModel //implements PiPedalModel
}
requestBankPresets(bankInstanceId: number): Promise<PresetIndexEntry[]> {
return nullCast(this.webSocket).request<PresetIndexEntry[]>("requestBankPresets", {bankInstanceId: bankInstanceId});
return nullCast(this.webSocket).request<PresetIndexEntry[]>("requestBankPresets", { bankInstanceId: bankInstanceId });
}
importPresetsFromBank(bankInstanceId: number, presets: number[]): Promise<number> {
return nullCast(this.webSocket).request<number>("importPresetsFromBank", {bankInstanceId: bankInstanceId, presets: presets});
return nullCast(this.webSocket).request<number>("importPresetsFromBank", { bankInstanceId: bankInstanceId, presets: presets });
}
copyPresetsToBank(bankInstanceId: number, presets: number[]): Promise<number> {
return nullCast(this.webSocket).request<number>("copyPresetsToBank", {bankInstanceId: bankInstanceId, presets: presets});
return nullCast(this.webSocket).request<number>("copyPresetsToBank", { bankInstanceId: bankInstanceId, presets: presets });
}
setPedalboardSideChainInput(instanceId: number, sideChainInputId: number): void {
let pedalboard = this.pedalboard.get().clone();
let pedalboardItem = pedalboard.getItem(instanceId);
if (!pedalboardItem)
{
if (!pedalboardItem) {
return;
}
pedalboardItem.sideChainInputId = sideChainInputId;
pedalboardItem.instanceId = ++pedalboard.nextInstanceId;
let oldId = pedalboardItem.instanceId;
let newId = ++pedalboard.nextInstanceId;
pedalboardItem.instanceId = newId; // force reload of pedalboard.
pedalboard.selectedPlugin = pedalboardItem.instanceId;
this.updateSidechainReferences(pedalboard, oldId, newId);
this.setModelPedalboard(pedalboard);
this.updateServerPedalboard();
}
removeInvalidSidechains(pedalboard: Pedalboard) {
let it = pedalboard.itemsGeneratorSplitAfter();
let previousItemIds: Set<number> = new Set<number>();
previousItemIds.add(-2); // start is visible.
while (true) {
let r = it.next();
if (r.done) {
break;
}
let item = r.value;
if (item.sideChainInputId !== -1) {
if (!previousItemIds.has(item.sideChainInputId)) {
item.sideChainInputId = -1;
}
}
if (!item.isEmpty()) { // empty items are not valid sidechain targets.
previousItemIds.add(item.instanceId);
}
}
}
updateSidechainReferences(pedalboard: Pedalboard, oldItemId: number, newItemId: number) {
let it = pedalboard.itemsGenerator();
while (true) {
let r = it.next();
if (r.done) break;
let item = r.value;
if (item.sideChainInputId === oldItemId) {
item.sideChainInputId = newItemId;
}
}
this.removeInvalidSidechains(pedalboard);
}
};
let instance: PiPedalModel | undefined = undefined;
+10 -5
View File
@@ -24,7 +24,7 @@ import CloseIcon from '@mui/icons-material/Close';
import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import CssBaseline from '@mui/material/CssBaseline';
import {createStyles} from './WithStyles';
import { createStyles } from './WithStyles';
import { withStyles } from "tss-react/mui";
import IconButtonEx from './IconButtonEx';
@@ -148,10 +148,12 @@ const SnapshotEditor = withStyles(
this.model_.zoomedUiControl.addOnChangedHandler(
() => {
this.setState({
zoomedControlOpen: this.model_.zoomedUiControl.get() !== undefined,
zoomedControlInfo: this.model_.zoomedUiControl.get()
});
if (this.mounted93) {
this.setState({
zoomedControlOpen: this.model_.zoomedUiControl.get() !== undefined,
zoomedControlInfo: this.model_.zoomedUiControl.get()
});
}
}
);
@@ -182,9 +184,11 @@ const SnapshotEditor = withStyles(
this.setState({ isFullScreen: !this.state.isFullScreen });
}
private mounted93: boolean = false;
componentDidMount() {
super.componentDidMount();
this.mounted93 = true;
this.model_.showStatusMonitor.addOnChangedHandler(this.showStatusMonitorHandler);
}
@@ -206,6 +210,7 @@ const SnapshotEditor = withStyles(
}
componentWillUnmount() {
this.mounted93 = false;
super.componentWillUnmount();
this.model_.banks.removeOnChangedHandler(this.showStatusMonitorHandler);
}