diff --git a/backend/Dockerfile b/backend/Dockerfile index 873fe2ca..caa4dbd3 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -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}" diff --git a/backend/src/models/subgraph_presets.rs b/backend/src/models/subgraph_presets.rs index f2a6c17d..ba8213e9 100644 --- a/backend/src/models/subgraph_presets.rs +++ b/backend/src/models/subgraph_presets.rs @@ -28,5 +28,5 @@ pub struct SerializedSubgraphPreset { )>, pub subgraphs: Vec<(Uuid, serde_json::Map)>, pub base_subgraph_id: Uuid, - pub connnecting_subgraph_id: Uuid, + pub connnecting_subgraph_id: Option, } diff --git a/engine/engine/src/js.rs b/engine/engine/src/js.rs index 6a75cf92..ac70fd94 100644 --- a/engine/engine/src/js.rs +++ b/engine/engine/src/js.rs @@ -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); diff --git a/engine/engine/src/lib.rs b/engine/engine/src/lib.rs index 8cea5720..473174b5 100644 --- a/engine/engine/src/lib.rs +++ b/engine/engine/src/lib.rs @@ -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() } diff --git a/engine/engine/src/view_context/manager.rs b/engine/engine/src/view_context/manager.rs index e19b61ab..2154ba68 100644 --- a/engine/engine/src/view_context/manager.rs +++ b/engine/engine/src/view_context/manager.rs @@ -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, } fn get_vc_key(uuid: Uuid) -> String { format!("vc_{}", uuid) } @@ -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 @@ -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::>(); SerializedSubgraph { @@ -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) + }, } } @@ -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: {}", @@ -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(); diff --git a/src/compositionSharing/CompositionSharing.tsx b/src/compositionSharing/CompositionSharing.tsx index 0a82dd03..9ceabd11 100644 --- a/src/compositionSharing/CompositionSharing.tsx +++ b/src/compositionSharing/CompositionSharing.tsx @@ -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; @@ -343,6 +344,9 @@ const CompositionSharing: React.FC = () => ( Load Composition + ); diff --git a/src/controls/GenericPresetPicker/GenericPresetPicker.scss b/src/controls/GenericPresetPicker/GenericPresetPicker.scss index 2bf1ec4e..2f4ff258 100644 --- a/src/controls/GenericPresetPicker/GenericPresetPicker.scss +++ b/src/controls/GenericPresetPicker/GenericPresetPicker.scss @@ -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; diff --git a/src/graphEditor/GraphEditor.tsx b/src/graphEditor/GraphEditor.tsx index 4718123e..d7b9a2cc 100644 --- a/src/graphEditor/GraphEditor.tsx +++ b/src/graphEditor/GraphEditor.tsx @@ -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({ @@ -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 { diff --git a/src/redux/modules/synthDesigner.ts b/src/redux/modules/synthDesigner.ts index 9012f5b9..a3ce0a8b 100644 --- a/src/redux/modules/synthDesigner.ts +++ b/src/redux/modules/synthDesigner.ts @@ -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 ); @@ -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, @@ -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()}`, }); diff --git a/src/vcInterop.ts b/src/vcInterop.ts index eec651e1..c16eba7b 100644 --- a/src/vcInterop.ts +++ b/src/vcInterop.ts @@ -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, @@ -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)); };