Fix preset loading not updating node graph editor
This commit is contained in:
parent
725faa4445
commit
16011e5f28
|
|
@ -698,6 +698,9 @@ struct EditorApp {
|
||||||
audio_controller: Option<std::sync::Arc<std::sync::Mutex<daw_backend::EngineController>>>,
|
audio_controller: Option<std::sync::Arc<std::sync::Mutex<daw_backend::EngineController>>>,
|
||||||
audio_event_rx: Option<rtrb::Consumer<daw_backend::AudioEvent>>,
|
audio_event_rx: Option<rtrb::Consumer<daw_backend::AudioEvent>>,
|
||||||
audio_events_pending: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
audio_events_pending: std::sync::Arc<std::sync::atomic::AtomicBool>,
|
||||||
|
/// Count of in-flight graph preset loads — keeps the repaint loop alive
|
||||||
|
/// until the audio thread sends GraphPresetLoaded events for all of them
|
||||||
|
pending_graph_loads: std::sync::Arc<std::sync::atomic::AtomicU32>,
|
||||||
#[allow(dead_code)] // Stored for future export/recording configuration
|
#[allow(dead_code)] // Stored for future export/recording configuration
|
||||||
audio_sample_rate: u32,
|
audio_sample_rate: u32,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -937,6 +940,7 @@ impl EditorApp {
|
||||||
audio_controller,
|
audio_controller,
|
||||||
audio_event_rx,
|
audio_event_rx,
|
||||||
audio_events_pending: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
|
audio_events_pending: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
|
||||||
|
pending_graph_loads: std::sync::Arc::new(std::sync::atomic::AtomicU32::new(0)),
|
||||||
audio_sample_rate,
|
audio_sample_rate,
|
||||||
audio_channels,
|
audio_channels,
|
||||||
video_manager: std::sync::Arc::new(std::sync::Mutex::new(
|
video_manager: std::sync::Arc::new(std::sync::Mutex::new(
|
||||||
|
|
@ -3976,6 +3980,10 @@ impl eframe::App for EditorApp {
|
||||||
if self.audio_events_pending.load(std::sync::atomic::Ordering::Relaxed) {
|
if self.audio_events_pending.load(std::sync::atomic::Ordering::Relaxed) {
|
||||||
ctx.request_repaint();
|
ctx.request_repaint();
|
||||||
}
|
}
|
||||||
|
// Keep repainting while waiting for graph preset loads to complete
|
||||||
|
if self.pending_graph_loads.load(std::sync::atomic::Ordering::Relaxed) > 0 {
|
||||||
|
ctx.request_repaint();
|
||||||
|
}
|
||||||
|
|
||||||
// Drain recording mirror buffer for live waveform display
|
// Drain recording mirror buffer for live waveform display
|
||||||
if self.is_recording {
|
if self.is_recording {
|
||||||
|
|
@ -4354,6 +4362,19 @@ impl eframe::App for EditorApp {
|
||||||
self.waveform_gpu_dirty.insert(pool_index);
|
self.waveform_gpu_dirty.insert(pool_index);
|
||||||
ctx.request_repaint();
|
ctx.request_repaint();
|
||||||
}
|
}
|
||||||
|
AudioEvent::GraphPresetLoaded(_track_id) => {
|
||||||
|
// Preset was loaded on the audio thread — bump generation
|
||||||
|
// so the node graph pane reloads from backend
|
||||||
|
self.project_generation += 1;
|
||||||
|
// Decrement pending counter (saturating to avoid underflow from
|
||||||
|
// loads not initiated by the preset browser, e.g. default instruments)
|
||||||
|
let _ = self.pending_graph_loads.fetch_update(
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
|v| if v > 0 { Some(v - 1) } else { Some(0) },
|
||||||
|
);
|
||||||
|
ctx.request_repaint();
|
||||||
|
}
|
||||||
_ => {} // Ignore other events for now
|
_ => {} // Ignore other events for now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4731,6 +4752,7 @@ impl eframe::App for EditorApp {
|
||||||
script_saved: &mut self.script_saved,
|
script_saved: &mut self.script_saved,
|
||||||
region_selection: &mut self.region_selection,
|
region_selection: &mut self.region_selection,
|
||||||
region_select_mode: &mut self.region_select_mode,
|
region_select_mode: &mut self.region_select_mode,
|
||||||
|
pending_graph_loads: &self.pending_graph_loads,
|
||||||
};
|
};
|
||||||
|
|
||||||
render_layout_node(
|
render_layout_node(
|
||||||
|
|
@ -5065,6 +5087,8 @@ struct RenderContext<'a> {
|
||||||
region_selection: &'a mut Option<lightningbeam_core::selection::RegionSelection>,
|
region_selection: &'a mut Option<lightningbeam_core::selection::RegionSelection>,
|
||||||
/// Region select mode (Rectangle or Lasso)
|
/// Region select mode (Rectangle or Lasso)
|
||||||
region_select_mode: &'a mut lightningbeam_core::tool::RegionSelectMode,
|
region_select_mode: &'a mut lightningbeam_core::tool::RegionSelectMode,
|
||||||
|
/// Counter for in-flight graph preset loads (keeps repaint loop alive)
|
||||||
|
pending_graph_loads: &'a std::sync::Arc<std::sync::atomic::AtomicU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively render a layout node with drag support
|
/// Recursively render a layout node with drag support
|
||||||
|
|
@ -5551,6 +5575,7 @@ fn render_pane(
|
||||||
script_saved: ctx.script_saved,
|
script_saved: ctx.script_saved,
|
||||||
region_selection: ctx.region_selection,
|
region_selection: ctx.region_selection,
|
||||||
region_select_mode: ctx.region_select_mode,
|
region_select_mode: ctx.region_select_mode,
|
||||||
|
pending_graph_loads: ctx.pending_graph_loads,
|
||||||
editing_clip_id: ctx.editing_clip_id,
|
editing_clip_id: ctx.editing_clip_id,
|
||||||
editing_instance_id: ctx.editing_instance_id,
|
editing_instance_id: ctx.editing_instance_id,
|
||||||
editing_parent_layer_id: ctx.editing_parent_layer_id,
|
editing_parent_layer_id: ctx.editing_parent_layer_id,
|
||||||
|
|
@ -5631,6 +5656,7 @@ fn render_pane(
|
||||||
script_saved: ctx.script_saved,
|
script_saved: ctx.script_saved,
|
||||||
region_selection: ctx.region_selection,
|
region_selection: ctx.region_selection,
|
||||||
region_select_mode: ctx.region_select_mode,
|
region_select_mode: ctx.region_select_mode,
|
||||||
|
pending_graph_loads: ctx.pending_graph_loads,
|
||||||
editing_clip_id: ctx.editing_clip_id,
|
editing_clip_id: ctx.editing_clip_id,
|
||||||
editing_instance_id: ctx.editing_instance_id,
|
editing_instance_id: ctx.editing_instance_id,
|
||||||
editing_parent_layer_id: ctx.editing_parent_layer_id,
|
editing_parent_layer_id: ctx.editing_parent_layer_id,
|
||||||
|
|
|
||||||
|
|
@ -237,6 +237,10 @@ pub struct SharedPaneState<'a> {
|
||||||
pub region_selection: &'a mut Option<lightningbeam_core::selection::RegionSelection>,
|
pub region_selection: &'a mut Option<lightningbeam_core::selection::RegionSelection>,
|
||||||
/// Region select mode (Rectangle or Lasso)
|
/// Region select mode (Rectangle or Lasso)
|
||||||
pub region_select_mode: &'a mut lightningbeam_core::tool::RegionSelectMode,
|
pub region_select_mode: &'a mut lightningbeam_core::tool::RegionSelectMode,
|
||||||
|
/// Counter for in-flight graph preset loads — increment when sending a
|
||||||
|
/// GraphLoadPreset command so the repaint loop stays alive until the
|
||||||
|
/// audio thread sends GraphPresetLoaded back
|
||||||
|
pub pending_graph_loads: &'a std::sync::Arc<std::sync::atomic::AtomicU32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for pane rendering
|
/// Trait for pane rendering
|
||||||
|
|
|
||||||
|
|
@ -191,8 +191,9 @@ impl PresetBrowserPane {
|
||||||
let mut controller = audio_controller.lock().unwrap();
|
let mut controller = audio_controller.lock().unwrap();
|
||||||
controller.graph_load_preset(track_id, preset.path.to_string_lossy().to_string());
|
controller.graph_load_preset(track_id, preset.path.to_string_lossy().to_string());
|
||||||
}
|
}
|
||||||
|
// Note: project_generation is incremented by the GraphPresetLoaded event handler
|
||||||
*shared.project_generation += 1;
|
// in main.rs, which fires after the audio thread has actually processed the load.
|
||||||
|
// This avoids a race where the node graph queries stale backend state.
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the save preset dialog
|
/// Render the save preset dialog
|
||||||
|
|
@ -509,6 +510,9 @@ impl PaneRenderer for PresetBrowserPane {
|
||||||
// Deferred actions after ScrollArea borrow is released
|
// Deferred actions after ScrollArea borrow is released
|
||||||
if let Some(idx) = load_index {
|
if let Some(idx) = load_index {
|
||||||
self.load_preset(idx, shared);
|
self.load_preset(idx, shared);
|
||||||
|
// Signal that we're expecting a GraphPresetLoaded event so the
|
||||||
|
// repaint loop stays alive until the audio thread responds.
|
||||||
|
shared.pending_graph_loads.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
if let Some(path) = delete_path {
|
if let Some(path) = delete_path {
|
||||||
if let Err(e) = std::fs::remove_file(&path) {
|
if let Err(e) = std::fs::remove_file(&path) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue