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