Skip to main content

bitcrusher/
bitcrusher.rs

1//! Example: BitCrusher node — quantization + sample-rate reduction
2//!
3//! Run with: cargo run --example bitcrusher -p aether-ndk
4
5use 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    // Internal state
14    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            // Sample-rate reduction
32            self.counter += 1.0;
33            if self.counter >= crush {
34                self.counter = 0.0;
35                // Bit quantization
36                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}