Skip to main content

proof_engine/audio/
mod.rs

1//! Mathematical audio — the same functions that drive visuals also drive sound.
2//!
3//! A MathAudioSource maps a MathFunction's output to audio frequency and amplitude.
4//! The visual and auditory are the same computation viewed through different senses.
5
6pub mod math_source;
7pub mod mixer;
8pub mod synth;
9pub mod output;
10pub mod music_engine;
11pub mod graph;
12pub mod effects;
13pub mod synthesis;
14pub mod spatial;
15
16use glam::Vec3;
17
18/// An audio event dispatched from game logic to the audio engine.
19#[derive(Clone, Debug)]
20pub enum AudioEvent {
21    /// Spawn a math-driven audio source at a 3D position.
22    SpawnSource { source: math_source::MathAudioSource, position: Vec3 },
23    /// Stop all sources associated with a tag.
24    StopTag(String),
25    /// Set master volume [0, 1].
26    SetMasterVolume(f32),
27    /// Set music volume [0, 1].
28    SetMusicVolume(f32),
29    /// Trigger a named one-shot sound effect.
30    PlaySfx { name: String, position: Vec3, volume: f32 },
31    /// Change the ambient music vibe.
32    SetMusicVibe(MusicVibe),
33}
34
35/// Named music vibes for CHAOS RPG compatibility.
36#[derive(Clone, Copy, Debug, PartialEq, Eq)]
37pub enum MusicVibe {
38    Title,
39    Exploration,
40    Combat,
41    BossFight,
42    Death,
43    Victory,
44    Silence,
45}
46
47/// The audio engine — spawns a cpal synthesis thread and accepts events.
48///
49/// If no audio device is available, `try_new()` returns None and all
50/// `emit()` calls are silently dropped (the engine runs fine without audio).
51pub struct AudioEngine {
52    sender: std::sync::mpsc::SyncSender<AudioEvent>,
53    _output: output::AudioOutput,
54}
55
56impl AudioEngine {
57    /// Open the default audio device and start the synthesis thread.
58    /// Returns None if no output device is available (runs silently).
59    pub fn try_new() -> Option<Self> {
60        let (tx, rx) = std::sync::mpsc::sync_channel(512);
61        let output = output::AudioOutput::try_new(rx)?;
62        Some(Self { sender: tx, _output: output })
63    }
64
65    /// Send an audio event to the synthesis thread. Non-blocking — drops if full.
66    pub fn emit(&self, event: AudioEvent) {
67        let _ = self.sender.try_send(event);
68    }
69}