Skip to content

Commit

Permalink
More work on subgraph implementation
Browse files Browse the repository at this point in the history
 * Subgraph portals switching back and forth between subgraphs is working
 * Fix various state sync and persistence issues
 * Work on setting up the subgraph portals for dynamic input/output routing
   * Modify placeholder output (was mis-named as placeholder input) to be generic and re-use it in subgraph portal
  • Loading branch information
Ameobea committed Feb 7, 2024
1 parent b0330f6 commit 11d4575
Show file tree
Hide file tree
Showing 15 changed files with 538 additions and 249 deletions.
1 change: 1 addition & 0 deletions engine/engine/src/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern "C" {
subgraphs_by_id_json: &str,
);
pub fn add_view_context(id: &str, name: &str, subgraph_id: &str);
pub fn add_foreign_connectable(fc_json: &str);
pub fn delete_view_context(id: &str);
pub fn set_active_vc_id(new_id: &str);
pub fn set_subgraphs(active_subgraph_id: &str, subgraphs_by_id_json: &str);
Expand Down
40 changes: 34 additions & 6 deletions engine/engine/src/view_context/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::str::FromStr;

use fxhash::FxHashMap;
use serde::{Deserialize, Serialize};
use serde_json::json;
use uuid::Uuid;

use crate::{
Expand Down Expand Up @@ -176,6 +177,13 @@ impl ViewContextManager {
created_ix
}

/// This triggers a fresh FC to get created on the frontend along with its associated node.
///
/// The frontend will then commit the FCs back here
fn add_foreign_connectable(&mut self, fc: ForeignConnectable) {
js::add_foreign_connectable(&serde_json::to_string(&fc).unwrap());
}

pub fn get_vc_by_id_mut(&mut self, uuid: Uuid) -> Option<&mut ViewContextEntry> {
self
.get_vc_position(uuid)
Expand Down Expand Up @@ -347,20 +355,40 @@ impl ViewContextManager {
.subgraphs_by_id
.insert(new_subgraph_id, SubgraphDescriptor {
id: new_subgraph_id,
name: format!("Subgraph {}", new_subgraph_id),
name: "New Subgraph".to_owned(),
active_vc_id: new_graph_editor_vc_id,
});
js::set_subgraphs(
&self.active_subgraph_id.to_string(),
&serde_json::to_string(&self.subgraphs_by_id).unwrap(),
);

// Start out the new subgraph with a graph editor
self.add_view_context(
new_graph_editor_vc_id,
"graph_editor".to_string(),
mk_graph_editor(new_graph_editor_vc_id),
new_subgraph_id,
);
self.save_all();
js::set_subgraphs(
&self.active_subgraph_id.to_string(),
&serde_json::to_string(&self.subgraphs_by_id).unwrap(),
);

// Add ssubgraph portals to and from the subgraph so the user can navigate between them
self.add_foreign_connectable(ForeignConnectable {
_type: "customAudio/subgraphPortal".to_owned(),
id: String::new(),
serialized_state: Some(
json!({ "txSubgraphID": self.active_subgraph_id, "rxSubgraphID": new_subgraph_id }),
),
subgraph_id: self.active_subgraph_id,
});
self.add_foreign_connectable(ForeignConnectable {
_type: "customAudio/subgraphPortal".to_owned(),
id: String::new(),
serialized_state: Some(
json!({ "txSubgraphID": new_subgraph_id, "rxSubgraphID": self.active_subgraph_id }),
),
subgraph_id: new_subgraph_id,
});

new_subgraph_id
}

Expand Down
75 changes: 0 additions & 75 deletions src/controlPanel/PlaceholderInput.tsx

This file was deleted.

98 changes: 98 additions & 0 deletions src/controlPanel/PlaceholderOutput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { OverridableAudioParam } from 'src/graphEditor/nodes/util';
import type { AudioConnectables, ConnectableDescriptor, ConnectableType } from 'src/patchNetwork';
import { updateConnectables } from 'src/patchNetwork/interface';
import type { MIDINode } from 'src/patchNetwork/midiNode';
import { actionCreators, dispatch, getState } from 'src/redux';

export class PlaceholderOutput extends GainNode implements AudioNode {
private vcId: string;
private getConnectables: () => AudioConnectables;
private addOutput: (
outputName: string,
type: ConnectableType,
rxConnectableDescriptor: ConnectableDescriptor
) => void;
public label: string;

constructor(
ctx: AudioContext,
vcId: string,
getConnectables: () => AudioConnectables,
addOutput: (
outputName: string,
type: ConnectableType,
rxConnectableDescriptor: ConnectableDescriptor
) => void,
label = 'Add a new control...'
) {
super(ctx);
this.vcId = vcId;
this.getConnectables = getConnectables;
this.addOutput = addOutput;
this.label = label;
}

connect(
destinationNode: AudioNode | AudioParam | MIDINode,
inputNumOrDescriptor?: number | ConnectableDescriptor,
_input?: number
) {
if (destinationNode instanceof OverridableAudioParam) {
destinationNode.setIsOverridden(true);
}
if (!inputNumOrDescriptor || typeof inputNumOrDescriptor === 'number') {
throw new Error(
'Must provide `ConnectableDescriptor` as second argument to `connect` for `PlaceholderOutput`'
);
}
const rxDescriptor = inputNumOrDescriptor;

setTimeout(() => {
// Disconnect from the dummy "add a new control", create a new input for it, and re-connect it to that

dispatch(
actionCreators.viewContextManager.DISCONNECT(
{ vcId: this.vcId, name: this.label },
rxDescriptor
)
);

let outputName = rxDescriptor.name;
while (
getState()
.viewContextManager.patchNetwork.connectables.get(this.vcId)
?.inputs.has(outputName)
) {
outputName += '_1';
}

const rxConnectables = getState().viewContextManager.patchNetwork.connectables.get(
rxDescriptor.vcId
);
if (!rxConnectables) {
throw new Error(`No connectables found for vcId=${rxDescriptor.vcId}`);
}
const rxConnectable = rxConnectables.inputs.get(rxDescriptor.name);
if (!rxConnectable) {
throw new Error(
`No input named "${rxDescriptor.name}" found for vcId=${rxDescriptor.vcId}`
);
}
this.addOutput(outputName, rxConnectable.type, rxDescriptor);

updateConnectables(this.vcId, this.getConnectables());
dispatch(
actionCreators.viewContextManager.CONNECT(
{ vcId: this.vcId, name: outputName },
rxDescriptor
)
);
});

return destinationNode as any;
}

disconnect(..._args: any) {
// no-op
}
}
28 changes: 25 additions & 3 deletions src/controlPanel/getConnectables.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Map as ImmMap } from 'immutable';

import { PlaceholderInput } from 'src/controlPanel/PlaceholderInput';
import type { AudioConnectables, ConnectableInput, ConnectableOutput } from 'src/patchNetwork';
import { PlaceholderOutput } from 'src/controlPanel/PlaceholderOutput';
import type {
AudioConnectables,
ConnectableDescriptor,
ConnectableInput,
ConnectableOutput,
ConnectableType,
} from 'src/patchNetwork';
import { actionCreators, dispatch, getState } from 'src/redux';
import type { ControlPanelInstanceState } from 'src/redux/modules/controlPanel';
import { UnimplementedError } from 'src/util';

Expand All @@ -22,7 +29,22 @@ export const buildControlPanelAudioConnectables = (

const outputs = existingConnections.set('Add a new control...', {
type: 'number',
node: new PlaceholderInput(ctx, vcId),
node: new PlaceholderOutput(
ctx,
vcId,
() => {
const instanceState = getState().controlPanel.stateByPanelInstance[vcId];
return buildControlPanelAudioConnectables(vcId, instanceState);
},
(inputName: string, type: ConnectableType, rxConnectableDescriptor: ConnectableDescriptor) =>
void dispatch(
actionCreators.controlPanel.ADD_CONTROL_PANEL_CONNECTION(
vcId,
rxConnectableDescriptor.vcId,
inputName
)
)
),
});

return {
Expand Down
Loading

0 comments on commit 11d4575

Please sign in to comment.