Skip to content

Commit

Permalink
Subgraph fixes
Browse files Browse the repository at this point in the history
 * Actually connect nodes created inside subgraphs being created
 * Fix synth designer init issue where mailbox IDs weren't set into the connectables after it was created until after refresh
 * Add ability to save full graph as a subgraph preset via composition sharing
   * Set the created subgraph ID to be the name of the preset in this case
  • Loading branch information
Ameobea committed Feb 12, 2024
1 parent eee5198 commit ffa093f
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 27 deletions.
2 changes: 1 addition & 1 deletion backend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ RUN apt-get update && apt-get install -y curl libmariadbclient-dev-compat build-

# Install rust
RUN curl https://sh.rustup.rs/ -sSf | \
sh -s -- -y --default-toolchain nightly-2022-08-10
sh -s -- -y --default-toolchain nightly-2024-02-02

ENV PATH="/root/.cargo/bin:${PATH}"

Expand Down
2 changes: 1 addition & 1 deletion backend/src/models/subgraph_presets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ pub struct SerializedSubgraphPreset {
)>,
pub subgraphs: Vec<(Uuid, serde_json::Map<String, serde_json::Value>)>,
pub base_subgraph_id: Uuid,
pub connnecting_subgraph_id: Uuid,
pub connnecting_subgraph_id: Option<Uuid>,
}
1 change: 1 addition & 0 deletions engine/engine/src/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extern "C" {
);
pub fn add_view_context(id: &str, name: &str, subgraph_id: &str);
pub fn add_foreign_connectable(fc_json: &str) -> String;
pub fn add_connection(from_vc_id: &str, from_port_name: &str, to_vc_id: &str, to_port_name: &str);
pub fn set_connections(connections_json: &str);
pub fn delete_foreign_connectable(id: &str);
pub fn delete_view_context(id: &str);
Expand Down
11 changes: 9 additions & 2 deletions engine/engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,17 @@ pub fn rename_subgraph(subgraph_id: &str, new_name: String) {
}

#[wasm_bindgen]
pub fn serialize_subgraph(subgraph_id: &str) -> String {
pub fn serialize_subgraph(subgraph_id: &str, subgraph_name_override: &str) -> String {
let uuid =
Uuid::from_str(subgraph_id).expect("Invalid UUID string passed to `serialize_subgraph`!");
let serialized = get_vcm().serialize_subgraph(uuid);
let serialized = get_vcm().serialize_subgraph(
uuid,
if subgraph_name_override.is_empty() {
None
} else {
Some(subgraph_name_override)
},
);
serde_json::to_string(&serialized).unwrap()
}

Expand Down
65 changes: 46 additions & 19 deletions engine/engine/src/view_context/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ pub struct SerializedSubgraph {
pub subgraphs: Vec<(Uuid, SubgraphDescriptor)>,
pub base_subgraph_id: Uuid,
/// ID of the subgraph which links to the subgraph being serialized
pub connnecting_subgraph_id: Uuid,
pub connnecting_subgraph_id: Option<Uuid>,
}

fn get_vc_key(uuid: Uuid) -> String { format!("vc_{}", uuid) }
Expand Down Expand Up @@ -644,9 +644,18 @@ impl ViewContextManager {
}

/// Assumes all frontend state has been committed to the backend already (`onBeforeUnload()`)
pub fn serialize_subgraph(&self, subgraph_id: Uuid) -> SerializedSubgraph {
let (_all_subgraph_connections, included_subgraph_ids) =
self.get_child_subgraph_ids(subgraph_id);
pub fn serialize_subgraph(
&self,
subgraph_id: Uuid,
subgraph_name_override: Option<&str>,
) -> SerializedSubgraph {
let included_subgraph_ids = if subgraph_id.is_nil() {
self.subgraphs_by_id.keys().cloned().collect()
} else {
let (_all_subgraph_connections, included_subgraph_ids) =
self.get_child_subgraph_ids(subgraph_id);
included_subgraph_ids
};

let fcs = self
.foreign_connectables
Expand Down Expand Up @@ -719,7 +728,15 @@ impl ViewContextManager {
.subgraphs_by_id
.iter()
.filter(|(id, _)| included_subgraph_ids.contains(id))
.map(|(id, desc)| (*id, desc.clone()))
.map(|(id, desc)| {
let mut desc = desc.clone();
if let Some(name_override) = subgraph_name_override {
if desc.id == subgraph_id {
desc.name = name_override.to_owned();
}
}
(*id, desc)
})
.collect::<Vec<_>>();

SerializedSubgraph {
Expand All @@ -728,7 +745,11 @@ impl ViewContextManager {
intra_conns,
subgraphs,
base_subgraph_id: subgraph_id,
connnecting_subgraph_id: self.active_subgraph_id,
connnecting_subgraph_id: if subgraph_id.is_nil() {
None
} else {
Some(self.active_subgraph_id)
},
}
}

Expand Down Expand Up @@ -784,7 +805,7 @@ impl ViewContextManager {
let rx_subgraph_uuid = Uuid::from_str(rx_subgraph_id).unwrap();
if fc.subgraph_id == serialized.base_subgraph_id
&& mapped_tx_subgraph_id == Some(serialized.base_subgraph_id)
&& rx_subgraph_uuid == serialized.connnecting_subgraph_id
&& Some(rx_subgraph_uuid) == serialized.connnecting_subgraph_id
{
info!(
"Re-pointing subgraph portal rx to active subgraph. Old ID: {}, new ID: {}",
Expand Down Expand Up @@ -904,23 +925,29 @@ impl ViewContextManager {
name: conn.1.name.clone(),
},
));
js::add_connection(&new_tx_id, &conn.0.name, &new_rx_id, &conn.1.name);
}
js::set_connections(&serde_json::to_string(&self.connections).unwrap());

// Finally, add a subgraph portal in the active subgraph pointing to the new subgraph with its
// inputs set to correspond to the one we re-pointed ealier
if let Some(base_portal_state) = base_portal_state {
let tx_subgraph_id = self.active_subgraph_id;
let rx_subgraph_id = serialized.base_subgraph_id;
let inputs = base_portal_state.get("registeredOutputs").cloned();
let outputs = base_portal_state.get("registeredInputs").cloned();
info!(
"Creating subgraph portal from active subgraph to new subgraph; tx={}, rx={}, \
inputs={:?}, outputs={:?}",
tx_subgraph_id, rx_subgraph_id, inputs, outputs
);
self.add_subgraph_portal(tx_subgraph_id, rx_subgraph_id, inputs, outputs);
}
let tx_subgraph_id = self.active_subgraph_id;
let rx_subgraph_id = serialized.base_subgraph_id;
let (inputs, outputs) = if let Some(base_portal_state) = base_portal_state {
(
base_portal_state.get("registeredOutputs").cloned(),
base_portal_state.get("registeredInputs").cloned(),
)
} else {
self.add_subgraph_portal(rx_subgraph_id, tx_subgraph_id, None, None);
(None, None)
};
info!(
"Creating subgraph portal from active subgraph to new subgraph; tx={}, rx={}, inputs={:?}, \
outputs={:?}",
tx_subgraph_id, rx_subgraph_id, inputs, outputs
);
self.add_subgraph_portal(tx_subgraph_id, rx_subgraph_id, inputs, outputs);

self.save_all();

Expand Down
6 changes: 5 additions & 1 deletion src/compositionSharing/CompositionSharing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import FlatButton from 'src/misc/FlatButton';
import { getState } from 'src/redux';
import { getSample, type SampleDescriptor } from 'src/sampleLibrary';
import { getSentry } from 'src/sentry';
import { getEngine } from 'src/util';
import { NIL_UUID, getEngine } from 'src/util';
import { saveSubgraphPreset } from 'src/graphEditor/GraphEditor';

export interface CompositionDefinition {
id: number;
Expand Down Expand Up @@ -343,6 +344,9 @@ const CompositionSharing: React.FC = () => (
Load Composition
</button>
</div>
<button style={{ marginTop: 40 }} onClick={() => saveSubgraphPreset(NIL_UUID, true)}>
Save as Subgraph
</button>
</div>
);

Expand Down
1 change: 1 addition & 0 deletions src/controls/GenericPresetPicker/GenericPresetPicker.scss
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
flex-direction: column;
width: calc(max(63vw, 600px));
height: calc(max(75vh, 450px));
min-height: 500px;

.generic-preset-saver-form {
display: flex;
Expand Down
11 changes: 9 additions & 2 deletions src/graphEditor/GraphEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ const confirmAndDeleteSubgraph = async (subgraphID: string) => {
getEngine()!.delete_subgraph(subgraphID);
};

const saveSubgraphPreset = async (subgraphID: string) => {
/**
* If `overrideName` is set to `true`, then the name of the created base subgraph will be set to
* the name of the preset.
*/
export const saveSubgraphPreset = async (subgraphID: string, overrideName = false) => {
let desc;
try {
desc = await renderGenericPresetSaverWithModal({
Expand All @@ -96,7 +100,10 @@ const saveSubgraphPreset = async (subgraphID: string) => {
// Commit all state to the engine
const engine = getEngine()!;
onBeforeUnload(engine);
const serializedSubgraph = getEngine()!.serialize_subgraph(subgraphID);
const serializedSubgraph = getEngine()!.serialize_subgraph(
subgraphID,
overrideName ? desc.name : ''
);
engine.init();

try {
Expand Down
5 changes: 4 additions & 1 deletion src/redux/modules/synthDesigner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ const disposeSynthModule = (synth: SynthModule) => {
synth.fmSynth.shutdown();
synth.outerGainNode.disconnect();
if (synth.filterOverrideStatusChangeCbs) {
console.log('de-registering');
synth.filterCSNs.frequency.deregisterOverrideStatusChangeCb(
synth.filterOverrideStatusChangeCbs.handleFrequencyOverrideStatusChange
);
Expand Down Expand Up @@ -254,6 +253,8 @@ const buildDefaultSynthModule = (
dispatch(actionCreators.synthDesigner.SET_FILTER_OVERRIDE_STATUS_CHANGE_CBS(synthIx, cbs));

connectFMSynth(stateKey, synthIx);

maybeUpdateMIDINode(getState().synthDesigner);
},
audioThreadMIDIEventMailboxID: `${vcId}-fm-synth-${genRandomStringID()}`,
useLegacyWavetableControls: false,
Expand Down Expand Up @@ -335,6 +336,8 @@ export const deserializeSynthModule = (
dispatch(actionCreators.synthDesigner.SET_FILTER_OVERRIDE_STATUS_CHANGE_CBS(synthIx, cbs));

connectFMSynth(stateKey, synthIx);

maybeUpdateMIDINode(getState().synthDesigner);
},
audioThreadMIDIEventMailboxID: `${vcId}-fm-synth-${genRandomStringID()}`,
});
Expand Down
20 changes: 20 additions & 0 deletions src/vcInterop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,12 @@ export const add_foreign_connectable = (fcJSON: string): string => {
return id;
};

/**
* Sets connections to match the engine.
*
* Does _NOT_ perform any actual connection/disconnection operations; it assumes that
* the patch network state already matches the provided list.
*/
export const set_connections = (connectionsJson: string) => {
const connections = tryParseJson<[ConnectableDescriptor, ConnectableDescriptor][]>(
connectionsJson,
Expand All @@ -106,6 +112,20 @@ export const set_connections = (connectionsJson: string) => {
dispatch(actionCreators.viewContextManager.SET_CONNECTIONS(connections));
};

export const add_connection = (
fromVcId: string,
fromPortName: string,
toVcId: string,
toPortName: string
) => {
dispatch(
actionCreators.viewContextManager.CONNECT(
{ vcId: fromVcId, name: fromPortName },
{ vcId: toVcId, name: toPortName }
)
);
};

export const delete_foreign_connectable = (id: string) => {
dispatch(actionCreators.viewContextManager.REMOVE_PATCH_NETWORK_NODE(id));
};
Expand Down

0 comments on commit ffa093f

Please sign in to comment.