1use std::collections::HashMap;
2
3#[cfg(not(target_arch = "wasm32"))]
4use wasmtime::{Engine, Instance, Linker, Module, Store, TypedFunc};
5
6#[cfg(not(target_arch = "wasm32"))]
7type RenderFunc = TypedFunc<(i32, i32, f32, f32, i32, i32, i32), ()>;
8
9#[cfg(not(target_arch = "wasm32"))]
10pub struct WasmPluginRunner {
11 engine: Engine,
12}
13
14#[cfg(not(target_arch = "wasm32"))]
15impl Default for WasmPluginRunner {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21#[cfg(not(target_arch = "wasm32"))]
22impl WasmPluginRunner {
23 pub fn new() -> Self {
24 let engine = Engine::default();
25 Self { engine }
26 }
27
28 pub fn process_in_place(&self, wasm_bytes: &[u8], buffer: &mut [f32]) -> Result<(), String> {
29 let module = Module::new(&self.engine, wasm_bytes)
30 .map_err(|e| format!("Failed to compile wasm: {e}"))?;
31
32 let mut store = Store::new(&self.engine, ());
33 let linker = Linker::new(&self.engine);
34
35 let instance = linker
36 .instantiate(&mut store, &module)
37 .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
38
39 let memory = instance
40 .get_memory(&mut store, "memory")
41 .ok_or_else(|| "WASM memory export not found".to_string())?;
42
43 let func = instance
44 .get_typed_func::<(i32, i32), ()>(&mut store, "process")
45 .map_err(|_| "Exported function `process(i32,i32)` not found".to_string())?;
46
47 let byte_len = std::mem::size_of_val(buffer) as i32;
48 let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
49 let mem_slice = memory
50 .data_mut(&mut store)
51 .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
52 .ok_or_else(|| "Failed to get memory slice".to_string())?;
53
54 let src_bytes =
55 unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
56 mem_slice.copy_from_slice(src_bytes);
57
58 func.call(&mut store, (ptr, buffer.len() as i32))
59 .map_err(|e| format!("Error calling `process`: {e}"))?;
60
61 let mem_slice_after = memory
62 .data(&store)
63 .get(ptr as usize..(ptr as usize) + (byte_len as usize))
64 .ok_or_else(|| "Failed to get memory slice after".to_string())?;
65 let dst_bytes = unsafe {
66 std::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, byte_len as usize)
67 };
68 dst_bytes.copy_from_slice(mem_slice_after);
69
70 Ok(())
71 }
72
73 pub fn render_note_in_place(
74 &self,
75 wasm_bytes: &[u8],
76 buffer: &mut [f32],
77 synth_name: Option<&str>,
78 freq: f32,
79 amp: f32,
80 duration_ms: i32,
81 sample_rate: i32,
82 channels: i32,
83 ) -> Result<(), String> {
84 let module = Module::new(&self.engine, wasm_bytes)
85 .map_err(|e| format!("Failed to compile wasm: {e}"))?;
86
87 let mut store = Store::new(&self.engine, ());
88 let linker = Linker::new(&self.engine);
89
90 let instance = linker
91 .instantiate(&mut store, &module)
92 .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
93
94 let memory = instance
95 .get_memory(&mut store, "memory")
96 .ok_or_else(|| "WASM memory export not found".to_string())?;
97
98 let mut func_opt: Option<RenderFunc> = None;
100 if let Some(name) = synth_name {
101 let specific = format!("render_note_{}", name);
102 if let Ok(f) = instance
103 .get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(&mut store, &specific)
104 {
105 func_opt = Some(f);
106 }
107 }
108 if func_opt.is_none() {
109 if let Ok(f) = instance.get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(
111 &mut store,
112 "render_note",
113 ) {
114 func_opt = Some(f);
115 }
116 }
117
118 let func =
119 func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
120
121 let byte_len = std::mem::size_of_val(buffer) as i32;
123 let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
124 let mem_slice = memory
125 .data_mut(&mut store)
126 .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
127 .ok_or_else(|| "Failed to get memory slice".to_string())?;
128 let src_bytes =
129 unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
130 mem_slice.copy_from_slice(src_bytes);
131
132 func.call(
134 &mut store,
135 (
136 ptr,
137 buffer.len() as i32,
138 freq,
139 amp,
140 duration_ms,
141 sample_rate,
142 channels,
143 ),
144 )
145 .map_err(|e| format!("Error calling `render_note`: {e}"))?;
146
147 let mem_slice_after = memory
149 .data(&store)
150 .get(ptr as usize..(ptr as usize) + (byte_len as usize))
151 .ok_or_else(|| "Failed to get memory slice after".to_string())?;
152 let dst_bytes = unsafe {
153 std::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, byte_len as usize)
154 };
155 dst_bytes.copy_from_slice(mem_slice_after);
156
157 Ok(())
158 }
159
160 pub fn render_note_with_params_in_place(
163 &self,
164 wasm_bytes: &[u8],
165 buffer: &mut [f32],
166 synth_name: Option<&str>,
167 freq: f32,
168 amp: f32,
169 duration_ms: i32,
170 sample_rate: i32,
171 channels: i32,
172 params_num: &HashMap<String, f32>,
173 params_str: Option<&HashMap<String, String>>,
174 ) -> Result<(), String> {
175 let module = Module::new(&self.engine, wasm_bytes)
176 .map_err(|e| format!("Failed to compile wasm: {e}"))?;
177
178 let mut store = Store::new(&self.engine, ());
179 let linker = Linker::new(&self.engine);
180
181 let instance = linker
182 .instantiate(&mut store, &module)
183 .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
184
185 let memory = instance
186 .get_memory(&mut store, "memory")
187 .ok_or_else(|| "WASM memory export not found".to_string())?;
188
189 for (k, v) in params_num.iter() {
191 let fname = format!("set_{}", k);
192 if let Ok(setter) = instance.get_typed_func::<f32, ()>(&mut store, &fname) {
193 let _ = setter.call(&mut store, *v);
194 }
195 }
196
197 if let Some(smap) = params_str {
199 for (k, v) in smap.iter() {
200 let fname = format!("set_{}_str", k);
201 if let Ok(setter) = instance.get_typed_func::<(i32, i32), ()>(&mut store, &fname) {
202 let bytes = v.as_bytes();
204 let ptr = Self::alloc_temp(&mut store, &instance, &memory, bytes.len())? as i32;
205 let mem_slice = memory
206 .data_mut(&mut store)
207 .get_mut(ptr as usize..(ptr as usize) + bytes.len())
208 .ok_or_else(|| "Failed to get memory slice for string".to_string())?;
209 mem_slice.copy_from_slice(bytes);
210 let _ = setter.call(&mut store, (ptr, bytes.len() as i32));
211 }
212 }
213 }
214
215 let mut func_opt: Option<RenderFunc> = None;
217 if let Some(name) = synth_name {
218 let specific = format!("render_note_{}", name);
219 if let Ok(f) = instance
220 .get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(&mut store, &specific)
221 {
222 func_opt = Some(f);
223 }
224 }
225 if func_opt.is_none() {
226 if let Ok(f) = instance.get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(
227 &mut store,
228 "render_note",
229 ) {
230 func_opt = Some(f);
231 }
232 }
233 let func =
234 func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
235
236 let byte_len = std::mem::size_of_val(buffer) as i32;
238 let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
239 let mem_slice = memory
240 .data_mut(&mut store)
241 .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
242 .ok_or_else(|| "Failed to get memory slice".to_string())?;
243 let src_bytes =
244 unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
245 mem_slice.copy_from_slice(src_bytes);
246
247 func.call(
249 &mut store,
250 (
251 ptr,
252 buffer.len() as i32,
253 freq,
254 amp,
255 duration_ms,
256 sample_rate,
257 channels,
258 ),
259 )
260 .map_err(|e| format!("Error calling `render_note`: {e}"))?;
261
262 let mem_slice_after = memory
264 .data(&store)
265 .get(ptr as usize..(ptr as usize) + (byte_len as usize))
266 .ok_or_else(|| "Failed to get memory slice after".to_string())?;
267 let dst_bytes = unsafe {
268 std::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, byte_len as usize)
269 };
270 dst_bytes.copy_from_slice(mem_slice_after);
271
272 Ok(())
273 }
274
275 fn alloc_temp(
276 store: &mut Store<()>,
277 instance: &Instance,
278 memory: &wasmtime::Memory,
279 size: usize,
280 ) -> Result<usize, String> {
281 if let Ok(malloc) = instance.get_typed_func::<i32, i32>(&mut *store, "__wbindgen_malloc") {
283 let ptr = malloc
284 .call(&mut *store, size as i32)
285 .map_err(|e| format!("malloc failed: {e}"))? as usize;
286 return Ok(ptr);
287 }
288
289 let current_len = memory.data_size(&mut *store);
291 let need = size;
292 let pages_needed = (current_len + need).div_ceil(0x10000) as u64; let current_pages = memory.size(&mut *store);
294 if pages_needed > current_pages {
295 let to_grow = pages_needed - current_pages;
296 memory
297 .grow(&mut *store, to_grow)
298 .map_err(|e| format!("memory.grow failed: {e}"))?;
299 }
300 Ok(current_len)
301 }
302}
303
304#[cfg(target_arch = "wasm32")]
306pub struct WasmPluginRunner;
307
308#[cfg(target_arch = "wasm32")]
309impl WasmPluginRunner {
310 pub fn new() -> Self {
311 WasmPluginRunner
312 }
313
314 pub fn process_in_place(&self, _wasm_bytes: &[u8], _buffer: &mut [f32]) -> Result<(), String> {
315 Err("Wasm plugin execution is not available in wasm builds".to_string())
316 }
317
318 pub fn render_note_in_place(
319 &self,
320 _wasm_bytes: &[u8],
321 _buffer: &mut [f32],
322 _synth_name: Option<&str>,
323 _freq: f32,
324 _amp: f32,
325 _duration_ms: i32,
326 _sample_rate: i32,
327 _channels: i32,
328 ) -> Result<(), String> {
329 Err("Wasm plugin rendering is not available in wasm builds".to_string())
330 }
331
332 pub fn render_note_with_params_in_place(
333 &self,
334 _wasm_bytes: &[u8],
335 _buffer: &mut [f32],
336 _synth_name: Option<&str>,
337 _freq: f32,
338 _amp: f32,
339 _duration_ms: i32,
340 _sample_rate: i32,
341 _channels: i32,
342 _params_num: &HashMap<String, f32>,
343 _params_str: Option<&HashMap<String, String>>,
344 ) -> Result<(), String> {
345 Err("Wasm plugin rendering is not available in wasm builds".to_string())
346 }
347}