devalang_core/core/plugin/runner/
non_wasm.rs1use std::collections::HashMap;
2
3use wasmtime::{Engine, Instance, Linker, Module, Store, TypedFunc};
4
5type RenderFunc = TypedFunc<(i32, i32, f32, f32, i32, i32, i32), ()>;
6
7pub struct WasmPluginRunner {
8 engine: Engine,
9}
10
11impl Default for WasmPluginRunner {
12 fn default() -> Self {
13 Self::new()
14 }
15}
16
17impl WasmPluginRunner {
18 pub fn new() -> Self {
19 let engine = Engine::default();
20 Self { engine }
21 }
22
23 pub fn process_in_place(&self, wasm_bytes: &[u8], buffer: &mut [f32]) -> Result<(), String> {
24 let module = Module::new(&self.engine, wasm_bytes)
25 .map_err(|e| format!("Failed to compile wasm: {e}"))?;
26
27 let mut store = Store::new(&self.engine, ());
28 let linker = Linker::new(&self.engine);
29
30 let instance = linker
31 .instantiate(&mut store, &module)
32 .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
33
34 let memory = instance
35 .get_memory(&mut store, "memory")
36 .ok_or_else(|| "WASM memory export not found".to_string())?;
37
38 let func = instance
39 .get_typed_func::<(i32, i32), ()>(&mut store, "process")
40 .map_err(|_| "Exported function `process(i32,i32)` not found".to_string())?;
41
42 let byte_len = std::mem::size_of_val(buffer) as i32;
43 let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
44 let mem_slice = memory
45 .data_mut(&mut store)
46 .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
47 .ok_or_else(|| "Failed to get memory slice".to_string())?;
48
49 let src_bytes =
50 unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
51 mem_slice.copy_from_slice(src_bytes);
52
53 func.call(&mut store, (ptr, buffer.len() as i32))
54 .map_err(|e| format!("Error calling `process`: {e}"))?;
55
56 let mem_slice_after = memory
57 .data(&store)
58 .get(ptr as usize..(ptr as usize) + (byte_len as usize))
59 .ok_or_else(|| "Failed to get memory slice after".to_string())?;
60 let dst_bytes = unsafe {
61 std::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, byte_len as usize)
62 };
63 dst_bytes.copy_from_slice(mem_slice_after);
64
65 Ok(())
66 }
67
68 pub fn render_note_in_place(
69 &self,
70 wasm_bytes: &[u8],
71 buffer: &mut [f32],
72 synth_name: Option<&str>,
73 freq: f32,
74 amp: f32,
75 duration_ms: i32,
76 sample_rate: i32,
77 channels: i32,
78 ) -> Result<(), String> {
79 let module = Module::new(&self.engine, wasm_bytes)
80 .map_err(|e| format!("Failed to compile wasm: {e}"))?;
81
82 let mut store = Store::new(&self.engine, ());
83 let linker = Linker::new(&self.engine);
84
85 let instance = linker
86 .instantiate(&mut store, &module)
87 .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
88
89 let memory = instance
90 .get_memory(&mut store, "memory")
91 .ok_or_else(|| "WASM memory export not found".to_string())?;
92
93 let mut func_opt: Option<RenderFunc> = None;
95 if let Some(name) = synth_name {
96 let specific = format!("render_note_{}", name);
97 if let Ok(f) = instance
98 .get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(&mut store, &specific)
99 {
100 func_opt = Some(f);
101 }
102 }
103 if func_opt.is_none() {
104 if let Ok(f) = instance.get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(
106 &mut store,
107 "render_note",
108 ) {
109 func_opt = Some(f);
110 }
111 }
112
113 let func =
114 func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
115
116 let byte_len = std::mem::size_of_val(buffer) as i32;
118 let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
119 let mem_slice = memory
120 .data_mut(&mut store)
121 .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
122 .ok_or_else(|| "Failed to get memory slice".to_string())?;
123 let src_bytes =
124 unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
125 mem_slice.copy_from_slice(src_bytes);
126
127 func.call(
129 &mut store,
130 (
131 ptr,
132 buffer.len() as i32,
133 freq,
134 amp,
135 duration_ms,
136 sample_rate,
137 channels,
138 ),
139 )
140 .map_err(|e| format!("Error calling `render_note`: {e}"))?;
141
142 let mem_slice_after = memory
144 .data(&store)
145 .get(ptr as usize..(ptr as usize) + (byte_len as usize))
146 .ok_or_else(|| "Failed to get memory slice after".to_string())?;
147 let dst_bytes = unsafe {
148 std::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, byte_len as usize)
149 };
150 dst_bytes.copy_from_slice(mem_slice_after);
151
152 Ok(())
153 }
154
155 pub fn render_note_with_params_in_place(
158 &self,
159 wasm_bytes: &[u8],
160 buffer: &mut [f32],
161 synth_name: Option<&str>,
162 freq: f32,
163 amp: f32,
164 duration_ms: i32,
165 sample_rate: i32,
166 channels: i32,
167 params_num: &HashMap<String, f32>,
168 params_str: Option<&HashMap<String, String>>,
169 ) -> Result<(), String> {
170 let module = Module::new(&self.engine, wasm_bytes)
171 .map_err(|e| format!("Failed to compile wasm: {e}"))?;
172
173 let mut store = Store::new(&self.engine, ());
174 let linker = Linker::new(&self.engine);
175
176 let instance = linker
177 .instantiate(&mut store, &module)
178 .map_err(|e| format!("Failed to instantiate wasm: {e}"))?;
179
180 let memory = instance
181 .get_memory(&mut store, "memory")
182 .ok_or_else(|| "WASM memory export not found".to_string())?;
183
184 for (k, v) in params_num.iter() {
186 let fname = format!("set_{}", k);
187 if let Ok(setter) = instance.get_typed_func::<f32, ()>(&mut store, &fname) {
188 let _ = setter.call(&mut store, *v);
189 }
190 }
191
192 if let Some(smap) = params_str {
194 for (k, v) in smap.iter() {
195 let fname = format!("set_{}_str", k);
196 if let Ok(setter) = instance.get_typed_func::<(i32, i32), ()>(&mut store, &fname) {
197 let bytes = v.as_bytes();
199 let ptr = Self::alloc_temp(&mut store, &instance, &memory, bytes.len())? as i32;
200 let mem_slice = memory
201 .data_mut(&mut store)
202 .get_mut(ptr as usize..(ptr as usize) + bytes.len())
203 .ok_or_else(|| "Failed to get memory slice for string".to_string())?;
204 mem_slice.copy_from_slice(bytes);
205 let _ = setter.call(&mut store, (ptr, bytes.len() as i32));
206 }
207 }
208 }
209
210 let mut func_opt: Option<RenderFunc> = None;
212 if let Some(name) = synth_name {
213 let specific = format!("render_note_{}", name);
214 if let Ok(f) = instance
215 .get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(&mut store, &specific)
216 {
217 func_opt = Some(f);
218 }
219 }
220 if func_opt.is_none() {
221 if let Ok(f) = instance.get_typed_func::<(i32, i32, f32, f32, i32, i32, i32), ()>(
222 &mut store,
223 "render_note",
224 ) {
225 func_opt = Some(f);
226 }
227 }
228 let func =
229 func_opt.ok_or_else(|| "Exported function `render_note` not found".to_string())?;
230
231 let byte_len = std::mem::size_of_val(buffer) as i32;
233 let ptr = Self::alloc_temp(&mut store, &instance, &memory, byte_len as usize)? as i32;
234 let mem_slice = memory
235 .data_mut(&mut store)
236 .get_mut(ptr as usize..(ptr as usize) + (byte_len as usize))
237 .ok_or_else(|| "Failed to get memory slice".to_string())?;
238 let src_bytes =
239 unsafe { std::slice::from_raw_parts(buffer.as_ptr() as *const u8, byte_len as usize) };
240 mem_slice.copy_from_slice(src_bytes);
241
242 func.call(
244 &mut store,
245 (
246 ptr,
247 buffer.len() as i32,
248 freq,
249 amp,
250 duration_ms,
251 sample_rate,
252 channels,
253 ),
254 )
255 .map_err(|e| format!("Error calling `render_note`: {e}"))?;
256
257 let mem_slice_after = memory
259 .data(&store)
260 .get(ptr as usize..(ptr as usize) + (byte_len as usize))
261 .ok_or_else(|| "Failed to get memory slice after".to_string())?;
262 let dst_bytes = unsafe {
263 std::slice::from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, byte_len as usize)
264 };
265 dst_bytes.copy_from_slice(mem_slice_after);
266
267 Ok(())
268 }
269
270 fn alloc_temp(
271 store: &mut Store<()>,
272 instance: &Instance,
273 memory: &wasmtime::Memory,
274 size: usize,
275 ) -> Result<usize, String> {
276 if let Ok(malloc) = instance.get_typed_func::<i32, i32>(&mut *store, "__wbindgen_malloc") {
278 let ptr = malloc
279 .call(&mut *store, size as i32)
280 .map_err(|e| format!("malloc failed: {e}"))? as usize;
281 return Ok(ptr);
282 }
283
284 let current_len = memory.data_size(&mut *store);
286 let need = size;
287 let pages_needed = (current_len + need).div_ceil(0x10000) as u64; let current_pages = memory.size(&mut *store);
289 if pages_needed > current_pages {
290 let to_grow = pages_needed - current_pages;
291 memory
292 .grow(&mut *store, to_grow)
293 .map_err(|e| format!("memory.grow failed: {e}"))?;
294 }
295 Ok(current_len)
296 }
297}