1use aether_ndk::prelude::*;
6
7#[aether_node]
8pub struct BitCrusher {
9 #[param(name = "Bits", min = 1.0, max = 16.0, default = 8.0)]
10 bits: f32,
11 #[param(name = "Rate Crush", min = 1.0, max = 32.0, default = 1.0)]
12 rate_crush: f32,
13 held_sample: f32,
15 counter: f32,
16}
17
18impl DspProcess for BitCrusher {
19 fn process(
20 &mut self,
21 inputs: &NodeInputs,
22 output: &mut NodeOutput,
23 params: &mut ParamBlock,
24 _sample_rate: f32,
25 ) {
26 let input = inputs.get(0);
27 for (i, out) in output.iter_mut().enumerate() {
28 let bits = params.get(0).current.clamp(1.0, 16.0);
29 let crush = params.get(1).current.clamp(1.0, 32.0);
30
31 self.counter += 1.0;
33 if self.counter >= crush {
34 self.counter = 0.0;
35 let levels = (2.0f32).powf(bits);
37 self.held_sample = (input[i] * levels).round() / levels;
38 }
39 *out = self.held_sample;
40 params.tick_all();
41 }
42 }
43
44 fn capture_state(&self) -> StateBlob {
45 #[repr(C)]
46 #[derive(Clone, Copy)]
47 struct S { held: f32, counter: f32 }
48 StateBlob::from_value(&S { held: self.held_sample, counter: self.counter })
49 }
50
51 fn restore_state(&mut self, state: StateBlob) {
52 #[repr(C)]
53 #[derive(Clone, Copy)]
54 struct S { held: f32, counter: f32 }
55 let s: S = state.to_value();
56 self.held_sample = s.held;
57 self.counter = s.counter;
58 }
59}
60
61fn main() {
62 println!("Node: {}", BitCrusher::type_name());
63 for def in BitCrusher::param_defs() {
64 println!(" {} [{:.0}–{:.0}] default={:.0}", def.name, def.min, def.max, def.default);
65 }
66 println!("\nBitCrusher ready ✓");
67}