Fix AI proxy origin in Tauri, SF2 program_select, VSTi GUI reopen + sample rate bridge
- aiGateway.js: use window.API_BASE_URL (engine port) instead of window.location.origin (tauri://localhost asset protocol returned index.html -> JSON parse error); check content-type before parsing response - NativeInstrumentEngine.cpp: fluid_synth_program_select for SF2 instrument + program change - Vst3Instrument.cpp: activate all audio/event buses, channel=0 forced, GUI resize/reopen, kEvent using fix - main.cpp: VST GUI reopen via WM_DESTROY, OleInitialize, steady_clock loop - lib.rs: BridgeSampleRate state, restart_bridge_with_sample_rate command, borrow fix - app.jsx/nativeBridgeService.js: isMidiTrack widening, bridge masterbus connect, held MIDI notes, sample-rate restart, openNativeGUI channel
This commit is contained in:
+49
-7
@@ -22,6 +22,7 @@ use shm::{Shm, ShmState};
|
||||
|
||||
struct EngineProcess(Mutex<Option<CommandChild>>);
|
||||
struct BridgeProcess(Mutex<Option<CommandChild>>);
|
||||
struct BridgeSampleRate(Mutex<u32>);
|
||||
|
||||
/// Kill the currently managed bridge child (if any) — a restart MUST never
|
||||
/// leave the old bridge running, else two daw_vst_bridge.exe race on the same
|
||||
@@ -129,12 +130,17 @@ fn spawn_bridge(
|
||||
}
|
||||
match found {
|
||||
Some((bridge_exe, label)) => {
|
||||
let sample_rate = {
|
||||
let rate_state = app.state::<BridgeSampleRate>();
|
||||
let g = rate_state.0.lock().unwrap_or_else(|p| p.into_inner());
|
||||
*g
|
||||
};
|
||||
match app
|
||||
.shell()
|
||||
.command(&bridge_exe)
|
||||
.env("SF_SHM_NAME", shm::SHM_NAME)
|
||||
.env("SF_PARENT_PID", std::process::id().to_string())
|
||||
.env("SF_SAMPLE_RATE", "44100") // B8: JS resampler handles mismatches (C5)
|
||||
.env("SF_SAMPLE_RATE", sample_rate.to_string())
|
||||
.env("SF_BLOCK_SIZE", "256")
|
||||
.spawn()
|
||||
{
|
||||
@@ -214,7 +220,8 @@ pub fn run() {
|
||||
load_native_instrument,
|
||||
open_vst_gui,
|
||||
bridge_status,
|
||||
transport_control
|
||||
transport_control,
|
||||
restart_bridge_with_sample_rate
|
||||
])
|
||||
.setup(|app| {
|
||||
let res_dir = app
|
||||
@@ -308,6 +315,7 @@ pub fn run() {
|
||||
if shm_created.is_some() { "created" } else { "unavailable (non-windows or error)" }
|
||||
);
|
||||
app.manage(ShmState(Mutex::new(shm_created)));
|
||||
app.manage(BridgeSampleRate(Mutex::new(48000)));
|
||||
|
||||
// Append bridge diagnostics to spawn.log and spawn the sidecar (B3).
|
||||
let app_handle = app.handle().clone();
|
||||
@@ -387,7 +395,7 @@ pub fn run() {
|
||||
}
|
||||
}
|
||||
drop(guard);
|
||||
std::thread::sleep(std::time::Duration::from_millis(5));
|
||||
std::thread::sleep(std::time::Duration::from_millis(1));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -509,7 +517,7 @@ fn load_native_instrument(app: AppHandle, path: String, instrument_type: u8, cha
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn open_vst_gui(app: AppHandle, plugin_id: String) -> Result<(), String> {
|
||||
fn open_vst_gui(app: AppHandle, plugin_id: String, channel: u8) -> Result<(), String> {
|
||||
// B9: bridge tự tạo native Win32 window cho editor VST3 (không qua
|
||||
// WebView2 — HTML window cũ vẽ ĐÈ lên GUI plugin). push_control(4,0,0,0)
|
||||
// với hwnd=0 báo bridge tạo window riêng trên ChannelWorker thread.
|
||||
@@ -518,8 +526,8 @@ fn open_vst_gui(app: AppHandle, plugin_id: String) -> Result<(), String> {
|
||||
match lock {
|
||||
Ok(guard) => match guard.as_ref() {
|
||||
Some(shm) => {
|
||||
let ok = shm.push_control(4, 0, 0, 0, &plugin_id);
|
||||
eprintln!("open_vst_gui: push_control type=4 hwnd=0 (bridge-native) ok={}", ok);
|
||||
let ok = shm.push_control(4, 0, 0, channel as u32, &plugin_id);
|
||||
eprintln!("open_vst_gui: push_control type=4 hwnd=0 ch={} ok={}", channel, ok);
|
||||
}
|
||||
None => eprintln!("open_vst_gui: bridge shm unavailable"),
|
||||
},
|
||||
@@ -557,7 +565,11 @@ fn bridge_status(app: AppHandle) -> Result<BridgeStatus, String> {
|
||||
write_index: shm.write_index(),
|
||||
block_timestamp: shm.block_timestamp(),
|
||||
shm_size_bytes: std::mem::size_of::<shm::SharedAudioBufferIPC>(),
|
||||
sample_rate: 44100,
|
||||
sample_rate: {
|
||||
let rate_state = app.state::<BridgeSampleRate>();
|
||||
let g = rate_state.0.lock().unwrap_or_else(|p| p.into_inner());
|
||||
*g
|
||||
},
|
||||
block_size: shm::AUDIO_BLOCK_SIZE as u32,
|
||||
},
|
||||
None => BridgeStatus {
|
||||
@@ -596,3 +608,33 @@ fn transport_control(app: AppHandle, kind: String, playhead: Option<u32>) -> Res
|
||||
.then_some(())
|
||||
.ok_or_else(|| "control queue full".to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn restart_bridge_with_sample_rate(app: AppHandle, sample_rate: u32) -> Result<(), String> {
|
||||
println!("restart_bridge_with_sample_rate: {}", sample_rate);
|
||||
{
|
||||
let rate_state = app.state::<BridgeSampleRate>();
|
||||
{
|
||||
let mut g = rate_state.0.lock().unwrap_or_else(|p| p.into_inner());
|
||||
*g = sample_rate;
|
||||
}
|
||||
}
|
||||
kill_bridge(&app);
|
||||
let res_dir = app.path().resource_dir().unwrap_or_default();
|
||||
let exe_dir = std::env::current_exe()
|
||||
.ok()
|
||||
.and_then(|p| p.parent().map(|d| d.to_path_buf()))
|
||||
.unwrap_or_default();
|
||||
let log_dir = std::env::var("APPDATA").unwrap_or_else(|_| ".".into());
|
||||
let spawn_log_path = std::path::Path::new(&log_dir)
|
||||
.join("SonicForgeDAW")
|
||||
.join("logs")
|
||||
.join("spawn.log");
|
||||
let mut log_line = format!("[tauri] restarting bridge with sample rate {}\n", sample_rate);
|
||||
let ok = spawn_bridge(&app, &res_dir, &exe_dir, &mut log_line, &spawn_log_path);
|
||||
if ok {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Failed to spawn bridge with new sample rate".into())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user