2026-03-24 13:37:27 +00:00

128 lines
2.8 KiB
Rust

use crate::model::Sample;
use std::sync::Arc;
pub const MAX_CHANNELS: usize = 16;
pub const OUTPUT_SAMPLE_RATE: u32 = 48000;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LoopMode {
Off,
On,
}
pub struct Channel {
pub sample: Option<Arc<Sample>>,
pub pos: f64,
pub pitch: f64,
pub volume: u8, // 0..255
pub pan: u8, // 0..255
pub loop_mode: LoopMode,
pub priority: u8,
}
impl Default for Channel {
fn default() -> Self {
Self {
sample: None,
pos: 0.0,
pitch: 1.0,
volume: 255,
pan: 127,
loop_mode: LoopMode::Off,
priority: 0,
}
}
}
pub enum AudioCommand {
Play {
sample: Arc<Sample>,
voice_id: usize,
volume: u8,
pan: u8,
pitch: f64,
priority: u8,
loop_mode: LoopMode,
},
Stop {
voice_id: usize,
},
SetVolume {
voice_id: usize,
volume: u8,
},
SetPan {
voice_id: usize,
pan: u8,
},
SetPitch {
voice_id: usize,
pitch: f64,
},
}
pub struct Audio {
pub voices: [Channel; MAX_CHANNELS],
pub commands: Vec<AudioCommand>,
}
impl Audio {
pub fn new() -> Self {
Self {
voices: Default::default(),
commands: Vec::new(),
}
}
pub fn play(&mut self, sample: Arc<Sample>, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) {
if voice_id < MAX_CHANNELS {
self.commands.push(AudioCommand::Play {
sample,
voice_id,
volume,
pan,
pitch,
priority,
loop_mode,
});
}
}
pub fn stop(&mut self, voice_id: usize) {
if voice_id < MAX_CHANNELS {
self.commands.push(AudioCommand::Stop { voice_id });
}
}
pub fn set_volume(&mut self, voice_id: usize, volume: u8) {
if voice_id < MAX_CHANNELS {
self.commands.push(AudioCommand::SetVolume { voice_id, volume });
}
}
pub fn set_pan(&mut self, voice_id: usize, pan: u8) {
if voice_id < MAX_CHANNELS {
self.commands.push(AudioCommand::SetPan { voice_id, pan });
}
}
pub fn set_pitch(&mut self, voice_id: usize, pitch: f64) {
if voice_id < MAX_CHANNELS {
self.commands.push(AudioCommand::SetPitch { voice_id, pitch });
}
}
pub fn is_playing(&self, voice_id: usize) -> bool {
if voice_id < MAX_CHANNELS {
self.voices[voice_id].sample.is_some()
} else {
false
}
}
/// Clears the command queue. The Host should consume this every frame.
pub fn clear_commands(&mut self) {
self.commands.clear();
}
}