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