Skip to main content

vibelang_dsp/
lib.rs

1//! VibeLang DSP - SynthDef generation and UGen DSL.
2//!
3//! This crate provides the synthesis definition layer for VibeLang:
4//!
5//! - **Graph** - Graph IR for synth construction (nodes, inputs, parameters)
6//! - **Encoder** - Binary encoding to SuperCollider's scsyndef format
7//! - **NodeRef** - Opaque node references with arithmetic operators
8//! - **Helpers** - High-level DSP functions (envelopes, mixing, etc.)
9//! - **UGens** - Auto-generated UGen function library
10//! - **Builder** - SynthDef builder for closure-based definition
11//! - **API** - Rhai API for define_synthdef and define_fx
12//!
13//! # Architecture
14//!
15//! SynthDefs are built using a thread-local graph builder pattern:
16//!
17//! 1. Set the active builder with [`set_active_builder`]
18//! 2. Add parameters, constants, and UGen nodes
19//! 3. Finalize with [`clear_active_builder`] and get the [`GraphIR`]
20//! 4. Encode to binary with [`encode_synthdef`]
21
22pub mod api;
23pub mod builder;
24pub mod encoder;
25pub mod errors;
26pub mod graph;
27pub mod helpers;
28pub mod rhainodes;
29pub mod system_synthdefs;
30
31// The UGen module is auto-generated by build.rs
32#[allow(clippy::too_many_arguments)]
33mod ugens {
34    include!(concat!(env!("OUT_DIR"), "/generated.rs"));
35}
36
37pub use api::{
38    clear_effect_registry, clear_modulator_registry, clear_synthdef_registry, effect_exists,
39    get_all_effects_encoded, get_all_modulators_encoded, get_all_synthdefs_encoded,
40    get_effect_param_defaults, get_modulator_param_defaults, get_synthdef_param_defaults,
41    modulator_synthdef_exists, register_synthdef_api, register_synthdef_ir, set_deploy_callback,
42    synthdef_exists, synthdef_or_effect_exists, FxBuilderHandle, ModulatorBuilderHandle,
43    SynthDefBuilderHandle,
44};
45pub use builder::SynthDef;
46pub use encoder::encode_synthdef;
47pub use errors::{Result, SynthDefError};
48pub use graph::{
49    clear_active_builder, set_active_builder, with_builder, GraphBuilderInner, GraphIR, Input,
50    ParamSpec, Rate, UGenNode,
51};
52pub use helpers::{
53    amp_to_db, channel, channels, db_to_amp, detune_spread, dup, env_gen, env_gen_with_env,
54    env_gen_with_env_n, in_ar, in_ar_n, mix, replace_out_ar, replace_out_ar_n, Env, EnvGenBuilder,
55};
56pub use rhainodes::{register_node_ref, NodeRef};
57
58/// Re-export the generated UGen registration function.
59pub use ugens::register_generated_ugens;
60
61/// Register all DSP types and functions with a Rhai engine.
62/// This includes UGens, NodeRef, helpers, and SynthDef builder API.
63pub fn register_dsp_api(engine: &mut rhai::Engine) {
64    register_node_ref(engine);
65    helpers::register_helpers(engine);
66    register_generated_ugens(engine);
67    register_synthdef_api(engine);
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn test_rate_ordering() {
76        assert!(Rate::Scalar < Rate::Control);
77        assert!(Rate::Control < Rate::Audio);
78    }
79
80    #[test]
81    fn test_input_constant() {
82        let input = Input::Constant(440.0);
83        if let Input::Constant(val) = input {
84            assert!((val - 440.0).abs() < 0.001);
85        } else {
86            panic!("Expected constant input");
87        }
88    }
89
90    #[test]
91    fn test_node_ref_encoding() {
92        let node_ref = NodeRef::new_with_output(5, 2);
93        assert_eq!(node_ref.id(), 5);
94        assert_eq!(node_ref.output_index(), 2);
95    }
96}