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}