aether_core/lib.rs
1//! # aether-core
2//!
3//! Hard real-time modular DSP engine — lock-free graph scheduler,
4//! generational arena, and zero-allocation buffer pool.
5//!
6//! ```
7//! 64-sample buffer · 48 kHz · ≤1.33 ms deadline · Zero allocations · Lock-free
8//! ```
9//!
10//! ## Architecture
11//!
12//! ```text
13//! Control thread RT audio thread
14//! ────────────── ───────────────
15//! AudioGraph (add/remove nodes) Scheduler::process_block()
16//! │ │
17//! │ CommandRing (SPSC) ├─ drain CommandRing
18//! └────────────────────────────────►│
19//! ├─ iterate sorted NodeArena
20//! ├─ borrow buffers from BufferPool
21//! └─ call DspNode::process() per node
22//! ```
23//!
24//! ## Real-time guarantees
25//!
26//! | Rule | Enforcement |
27//! |---|---|
28//! | No heap allocation | Pre-allocated arena + buffer pool |
29//! | No locks | SPSC ring buffer (`ringbuf`) |
30//! | No I/O | All I/O on control/tokio threads |
31//! | Bounded execution | Flat topo-sorted array, ≤32 commands/tick |
32//!
33//! ## Quick start
34//!
35//! See [`node::DspNode`] to implement a processing node, [`graph::AudioGraph`]
36//! to build a patch, and [`scheduler::Scheduler`] to drive the RT loop.
37
38pub mod arena;
39pub mod buffer_pool;
40pub mod command;
41pub mod graph;
42pub mod node;
43pub mod param;
44pub mod scheduler;
45pub mod state;
46
47/// Audio buffer size in samples. Hard real-time constraint: 64 samples @ 48kHz = 1.33ms deadline.
48pub const BUFFER_SIZE: usize = 64;
49
50/// Maximum number of inputs per node. Kept small to fit in cache lines.
51pub const MAX_INPUTS: usize = 8;
52
53/// Maximum number of nodes in the arena. Pre-allocated at startup.
54pub const MAX_NODES: usize = 10_240;
55
56/// Maximum number of audio buffers in the pool.
57pub const MAX_BUFFERS: usize = MAX_NODES * 2;
58
59/// Maximum commands processed per audio callback. Bounds mutation cost.
60pub const MAX_COMMANDS_PER_TICK: usize = 32;
61
62/// Command ring buffer capacity.
63pub const COMMAND_RING_CAPACITY: usize = 1024;