1use core::marker::PhantomData;
2
3use super::*;
4
5pub struct Sine {}
7pub struct Mix {}
9pub struct AllForOne {}
11pub struct Gain {}
13pub struct Loop {}
15pub struct Concat {}
17pub struct Pan {}
19pub struct Mute {}
21pub struct Pause {}
23pub struct TrackPosition {}
25pub struct LowPass {}
27pub struct HighPass {}
29pub struct TakeLeft {}
31pub struct TakeRight {}
33pub struct Swap {}
35pub struct Clip {}
37pub struct Square {}
39pub struct Sawtooth {}
41pub struct Triangle {}
43pub struct Noise {}
45pub struct Empty {}
47pub struct Zero {}
49
50pub struct File {}
52
53pub struct Node<F> {
55 id: u32,
56 _flavor: PhantomData<F>,
58}
59
60pub const OUT: Node<Mix> = Node::new(0);
62
63#[expect(clippy::must_use_candidate)]
64impl<F> Node<F> {
65 #[must_use]
66 const fn new(id: u32) -> Self {
67 Self {
68 id,
69 _flavor: PhantomData,
70 }
71 }
72
73 pub fn add_sine(&self, f: Freq, phase: f32) -> Node<Sine> {
75 let id = unsafe { bindings::add_sine(self.id, f.0, phase) };
76 Node::new(id)
77 }
78
79 pub fn add_square(&self, f: Freq, phase: f32) -> Node<Square> {
81 let id = unsafe { bindings::add_square(self.id, f.0, phase) };
82 Node::new(id)
83 }
84
85 pub fn add_sawtooth(&self, f: Freq, phase: f32) -> Node<Sawtooth> {
87 let id = unsafe { bindings::add_sawtooth(self.id, f.0, phase) };
88 Node::new(id)
89 }
90
91 pub fn add_triangle(&self, f: Freq, phase: f32) -> Node<Triangle> {
93 let id = unsafe { bindings::add_triangle(self.id, f.0, phase) };
94 Node::new(id)
95 }
96
97 pub fn add_noise(&self, seed: i32) -> Node<Noise> {
99 let id = unsafe { bindings::add_noise(self.id, seed) };
100 Node::new(id)
101 }
102
103 pub fn add_empty(&self) -> Node<Empty> {
105 let id = unsafe { bindings::add_empty(self.id) };
106 Node::new(id)
107 }
108
109 pub fn add_zero(&self) -> Node<Zero> {
111 let id = unsafe { bindings::add_zero(self.id) };
112 Node::new(id)
113 }
114
115 pub fn add_file(&self, path: &str) -> Node<File> {
117 let ptr = path.as_ptr() as u32;
118 let len = path.len() as u32;
119 let id = unsafe { bindings::add_file(self.id, ptr, len) };
120 Node::new(id)
121 }
122
123 pub fn add_mix(&self) -> Node<Mix> {
125 let id = unsafe { bindings::add_mix(self.id) };
126 Node::new(id)
127 }
128
129 pub fn add_all_for_one(&self) -> Node<AllForOne> {
131 let id = unsafe { bindings::add_all_for_one(self.id) };
132 Node::new(id)
133 }
134
135 pub fn add_gain(&self, lvl: f32) -> Node<Gain> {
137 let id = unsafe { bindings::add_gain(self.id, lvl) };
138 Node::new(id)
139 }
140
141 pub fn add_loop(&self) -> Node<Loop> {
143 let id = unsafe { bindings::add_loop(self.id) };
144 Node::new(id)
145 }
146
147 pub fn add_concat(&self) -> Node<Concat> {
149 let id = unsafe { bindings::add_concat(self.id) };
150 Node::new(id)
151 }
152
153 pub fn add_pan(&self, lvl: f32) -> Node<Pan> {
155 let id = unsafe { bindings::add_pan(self.id, lvl) };
156 Node::new(id)
157 }
158
159 pub fn add_mute(&self) -> Node<Mute> {
161 let id = unsafe { bindings::add_mute(self.id) };
162 Node::new(id)
163 }
164
165 pub fn add_pause(&self) -> Node<Pause> {
167 let id = unsafe { bindings::add_pause(self.id) };
168 Node::new(id)
169 }
170
171 pub fn add_track_position(&self) -> Node<TrackPosition> {
173 let id = unsafe { bindings::add_track_position(self.id) };
174 Node::new(id)
175 }
176
177 pub fn add_low_pass(&self, freq: f32, q: f32) -> Node<LowPass> {
179 let id = unsafe { bindings::add_low_pass(self.id, freq, q) };
180 Node::new(id)
181 }
182
183 pub fn add_high_pass(&self, freq: f32, q: f32) -> Node<HighPass> {
185 let id = unsafe { bindings::add_high_pass(self.id, freq, q) };
186 Node::new(id)
187 }
188
189 pub fn add_take_left(&self) -> Node<TakeLeft> {
191 let id = unsafe { bindings::add_take_left(self.id) };
192 Node::new(id)
193 }
194
195 pub fn add_take_right(&self) -> Node<TakeRight> {
197 let id = unsafe { bindings::add_take_right(self.id) };
198 Node::new(id)
199 }
200
201 pub fn add_swap(&self) -> Node<Swap> {
203 let id = unsafe { bindings::add_swap(self.id) };
204 Node::new(id)
205 }
206
207 pub fn add_clip(&self, low: f32, high: f32) -> Node<Clip> {
209 let id = unsafe { bindings::add_clip(self.id, low, high) };
210 Node::new(id)
211 }
212
213 pub fn reset(&self) {
215 unsafe { bindings::reset(self.id) }
216 }
217
218 pub fn reset_all(&self) {
220 unsafe { bindings::reset_all(self.id) }
221 }
222
223 pub fn clear(&self) {
228 unsafe { bindings::clear(self.id) }
229 }
230}
231
232impl Node<Sine> {
233 pub fn modulate<M: Modulator>(&self, m: M) {
235 m.modulate(self.id, 0);
236 }
237}
238
239impl Node<Square> {
240 pub fn modulate<M: Modulator>(&self, m: M) {
242 m.modulate(self.id, 0);
243 }
244}
245
246impl Node<Sawtooth> {
247 pub fn modulate<M: Modulator>(&self, m: M) {
249 m.modulate(self.id, 0);
250 }
251}
252
253impl Node<Triangle> {
254 pub fn modulate<M: Modulator>(&self, m: M) {
256 m.modulate(self.id, 0);
257 }
258}
259
260impl Node<Gain> {
261 pub fn modulate<M: Modulator>(&self, m: M) {
263 m.modulate(self.id, 0);
264 }
265}
266
267impl Node<Pan> {
268 pub fn modulate<M: Modulator>(&self, m: M) {
270 m.modulate(self.id, 0);
271 }
272}
273
274impl Node<Mute> {
275 pub fn modulate<M: Modulator>(&self, m: M) {
279 m.modulate(self.id, 0);
280 }
281}
282
283impl Node<Pause> {
284 pub fn modulate<M: Modulator>(&self, m: M) {
288 m.modulate(self.id, 0);
289 }
290}
291
292impl Node<LowPass> {
293 pub fn modulate_freq<M: Modulator>(&self, m: M) {
295 m.modulate(self.id, 0);
296 }
297}
298
299impl Node<HighPass> {
300 pub fn modulate_freq<M: Modulator>(&self, m: M) {
302 m.modulate(self.id, 0);
303 }
304}
305
306impl Node<Clip> {
307 pub fn modulate_both<M: Modulator>(&self, m: M) {
311 m.modulate(self.id, 0);
312 }
313
314 pub fn modulate_low<M: Modulator>(&self, m: M) {
316 m.modulate(self.id, 1);
317 }
318
319 pub fn modulate_high<M: Modulator>(&self, m: M) {
321 m.modulate(self.id, 2);
322 }
323}
324
325mod bindings {
326 #[link(wasm_import_module = "audio")]
327 extern {
328 pub(super) fn add_sine(parent_id: u32, freq: f32, phase: f32) -> u32;
330 pub(super) fn add_square(parent_id: u32, freq: f32, phase: f32) -> u32;
331 pub(super) fn add_sawtooth(parent_id: u32, freq: f32, phase: f32) -> u32;
332 pub(super) fn add_triangle(parent_id: u32, freq: f32, phase: f32) -> u32;
333 pub(super) fn add_noise(parent_id: u32, seed: i32) -> u32;
334 pub(super) fn add_empty(parent_id: u32) -> u32;
335 pub(super) fn add_zero(parent_id: u32) -> u32;
336 pub(super) fn add_file(parent: u32, ptr: u32, len: u32) -> u32;
337
338 pub(super) fn add_mix(parent_id: u32) -> u32;
340 pub(super) fn add_all_for_one(parent_id: u32) -> u32;
341 pub(super) fn add_gain(parent_id: u32, lvl: f32) -> u32;
342 pub(super) fn add_loop(parent_id: u32) -> u32;
343 pub(super) fn add_concat(parent_id: u32) -> u32;
344 pub(super) fn add_pan(parent_id: u32, lvl: f32) -> u32;
345 pub(super) fn add_mute(parent_id: u32) -> u32;
346 pub(super) fn add_pause(parent_id: u32) -> u32;
347 pub(super) fn add_track_position(parent_id: u32) -> u32;
348 pub(super) fn add_low_pass(parent_id: u32, freq: f32, q: f32) -> u32;
349 pub(super) fn add_high_pass(parent_id: u32, freq: f32, q: f32) -> u32;
350 pub(super) fn add_take_left(parent_id: u32) -> u32;
351 pub(super) fn add_take_right(parent_id: u32) -> u32;
352 pub(super) fn add_swap(parent_id: u32) -> u32;
353 pub(super) fn add_clip(parent_id: u32, low: f32, high: f32) -> u32;
354
355 pub(super) fn reset(node_id: u32);
356 pub(super) fn reset_all(node_id: u32);
357 pub(super) fn clear(node_id: u32);
358 }
359}