Skip to main content

tono_core/runtime/
mod.rs

1//! runtime — the embeddable real-time control surface over the deterministic engine.
2//!
3//! The idiomatic library API a game (or any host) drives: [`Engine::load`] a
4//! [`SoundDoc`](crate::dsl::SoundDoc) (or [`Engine::load_patch`] a [`Patch`](crate::patch::Patch) with named parameters) as
5//! a reusable **resource**, [`Engine::play`] as many independent **instances** as
6//! you like, and control each by its [`InstanceHandle`] with [`Tween`]-smoothed
7//! setters. Host output adapters (cpal, an AudioWorklet, a Bevy source) target
8//! the [`AudioSource`] trait, so they never depend on a concrete engine type.
9//!
10//! Backed today by the deterministic buffer renderer ([`crate::player::Player`]),
11//! which keeps the mix **byte-identical to an offline bounce**. Instance master
12//! controls (gain / pan / stop) apply live per block; parameter and layer-gain
13//! changes ([`Engine::set_param`] / [`Engine::set_layer_gain`]) re-render the
14//! instance and **crossfade** for a click-free swap — control-rate today, and
15//! sample-accurate once the stateful streaming renderer lands behind this same
16//! seam. Multi-threaded real-time use goes through [`Engine::split`].
17//!
18//! # Adapters
19//!
20//! A host output is a thin shim over [`AudioSource`] + [`Engine::split`]. cpal:
21//!
22//! ```ignore
23//! let (mut control, mut audio) = Engine::new(sr).split(2048);
24//! let stream = device.build_output_stream(
25//!     &config,
26//!     move |out: &mut [f32], _| { audio.fill(out); }, // audio thread drains the ring
27//!     err_fn, None,
28//! )?;
29//! stream.play()?;
30//! // On a control thread: loop { control.pump(1024); std::thread::sleep(dt); }
31//! ```
32//!
33//! A Bevy `Decodable` / rodio `Source` wraps the same [`Renderer`]; an
34//! AudioWorklet calls [`AudioSource::fill`] on each 128-frame quantum.
35
36mod engine;
37mod mixer;
38pub mod performance;
39mod ring;
40mod source;
41mod transport;
42
43/// Pre-allocated scratch depth (frames) shared by the runtime's `fill` paths
44/// ([`Engine`], [`Mixer`], [`StreamSource`]): covers any host block up to this
45/// size without allocating in the audio callback; a larger block grows the
46/// scratch once, on the first such call.
47pub const SCRATCH_FRAMES: usize = 8192;
48
49pub use engine::{Engine, InstanceHandle, LayerId, ParamId, PatchId, Priority, Tween};
50pub use mixer::{BusId, Mixer, MixerError, SourceId};
51pub use performance::{
52    At, Command, Performance, PerformanceError, PerformanceMetrics, TimestampedCommand,
53};
54pub use ring::{Controller, Pump, Renderer, spsc};
55pub use source::{AudioSource, StreamSource, write_interleaved};
56pub use transport::{Advance, Transport, TransportState};
57
58#[cfg(test)]
59mod tests;