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}