moa/emulator/frontends/common/src/audio.rs

199 lines
5.3 KiB
Rust
Raw Normal View History

use std::sync::{Arc, Mutex, MutexGuard};
2024-02-24 21:02:09 +00:00
use femtos::{Instant, Duration};
use moa_host::{Audio, Sample, AudioFrame, ClockedQueue};
pub const SAMPLE_RATE: usize = 48000;
pub struct AudioSource {
2022-10-08 20:26:17 +00:00
id: usize,
sample_rate: usize,
2022-10-08 20:26:17 +00:00
queue: ClockedQueue<AudioFrame>,
}
impl AudioSource {
// TODO should you move this to AudioMixer to make the interface easier to use?
// ie. let source: AudioSource = mixer.new_source();
pub fn new(mixer: AudioMixer) -> Self {
let queue = ClockedQueue::new(5000);
let (id, sample_rate) = {
let mut mixer = mixer.borrow_mut();
2022-10-08 20:26:17 +00:00
let id = mixer.add_source(queue.clone());
(id, mixer.sample_rate())
2022-10-08 20:26:17 +00:00
};
Self {
2022-10-08 20:26:17 +00:00
id,
sample_rate,
2022-10-08 20:26:17 +00:00
queue,
}
}
2022-10-09 04:32:59 +00:00
pub fn id(&self) -> usize {
self.id
}
2024-02-24 21:02:09 +00:00
pub fn add_frame(&mut self, clock: Instant, buffer: &[Sample]) {
let mut data = Vec::with_capacity(buffer.len());
for sample in buffer.iter() {
data.push(*sample);
}
2022-10-08 20:26:17 +00:00
let frame = AudioFrame::new(self.sample_rate, data);
2022-10-08 20:26:17 +00:00
self.queue.push(clock, frame);
}
}
2022-10-08 20:26:17 +00:00
impl Audio for AudioSource {
fn samples_per_second(&self) -> usize {
self.sample_rate
}
2024-02-24 21:02:09 +00:00
fn write_samples(&mut self, clock: Instant, buffer: &[Sample]) {
2022-10-11 17:28:59 +00:00
self.add_frame(clock, buffer);
}
}
#[derive(Clone)]
pub struct AudioMixer(Arc<Mutex<AudioMixerInner>>);
pub struct AudioMixerInner {
sample_rate: usize,
2022-10-08 20:26:17 +00:00
sources: Vec<ClockedQueue<AudioFrame>>,
output: AudioOutput,
}
impl AudioMixer {
pub fn new(sample_rate: usize) -> AudioMixer {
AudioMixer(Arc::new(Mutex::new(AudioMixerInner {
sample_rate,
2022-10-08 20:26:17 +00:00
sources: vec![],
output: AudioOutput::default(),
})))
}
pub fn with_default_rate() -> AudioMixer {
AudioMixer::new(SAMPLE_RATE)
}
pub fn borrow_mut(&self) -> MutexGuard<'_, AudioMixerInner> {
self.0.lock().unwrap()
}
}
impl AudioMixerInner {
2022-10-08 20:26:17 +00:00
pub fn add_source(&mut self, source: ClockedQueue<AudioFrame>) -> usize {
self.sources.push(source);
self.sources.len() - 1
}
pub fn num_sources(&self) -> usize {
self.sources.len()
}
pub fn get_sink(&mut self) -> AudioOutput {
2022-10-08 20:26:17 +00:00
self.output.clone()
}
pub fn sample_rate(&self) -> usize {
self.sample_rate
}
2024-02-24 21:02:09 +00:00
pub fn sample_duration(&self) -> Duration {
Duration::from_secs(1) / self.sample_rate as u64
2022-10-08 20:26:17 +00:00
}
2024-02-24 21:02:09 +00:00
fn assemble_frame(&mut self, frame_start: Instant, frame_duration: Duration) {
let sample_duration = self.sample_duration();
let samples = (frame_duration / sample_duration) as usize;
let mut data = vec![Sample(0.0, 0.0); samples];
for source in &self.sources {
let mut index = 0;
while index < data.len() {
if let Some((clock, mut frame)) = source.pop_next() {
index = (clock.duration_since(frame_start) / sample_duration) as usize;
let size = frame.data.len().min(data.len() - index);
frame
.data
.iter()
.zip(&mut data[index..index + size])
.for_each(|(source, dest)| {
dest.0 += source.0;
dest.1 += source.1;
});
index += size;
if size < frame.data.len() {
frame.data.drain(0..size);
source.put_back(clock, frame);
}
}
}
}
2022-10-08 20:26:17 +00:00
// Average each sample, and clamp it to the 1 to -1 range
for sample in data.iter_mut() {
sample.0 = (sample.0 / self.sources.len() as f32).clamp(-1.0, 1.0);
sample.1 = (sample.1 / self.sources.len() as f32).clamp(-1.0, 1.0);
2022-10-08 20:26:17 +00:00
}
self.output.add_frame(frame_start, AudioFrame::new(self.sample_rate, data));
}
}
2022-10-08 20:26:17 +00:00
use moa_core::{Transmutable, Steppable, Error, System};
2022-10-08 20:26:17 +00:00
impl Steppable for AudioMixer {
2024-02-24 21:02:09 +00:00
fn step(&mut self, system: &System) -> Result<Duration, Error> {
let duration = Duration::from_millis(1);
// TODO should you make the clock be even further back to ensure the data is already written
if let Some(start) = system.clock.checked_sub(duration) {
self.borrow_mut().assemble_frame(start, duration);
2022-10-08 20:26:17 +00:00
}
Ok(duration)
}
}
2022-10-08 20:26:17 +00:00
impl Transmutable for AudioMixer {
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
Some(self)
}
}
// TODO this should be split up into a sender/receiver
#[derive(Clone)]
pub struct AudioOutput {
queue: ClockedQueue<AudioFrame>,
}
impl Default for AudioOutput {
fn default() -> Self {
Self {
queue: ClockedQueue::new(5000),
}
}
}
impl AudioOutput {
2024-02-24 21:02:09 +00:00
pub fn add_frame(&self, clock: Instant, frame: AudioFrame) {
self.queue.push(clock, frame);
2022-10-08 20:26:17 +00:00
}
2024-02-24 21:02:09 +00:00
pub fn put_back(&self, clock: Instant, frame: AudioFrame) {
self.queue.put_back(clock, frame);
2022-10-08 20:26:17 +00:00
}
2024-02-24 21:02:09 +00:00
pub fn receive(&self) -> Option<(Instant, AudioFrame)> {
self.queue.pop_next()
2022-10-08 20:26:17 +00:00
}
pub fn is_empty(&self) -> bool {
self.queue.is_empty()
2022-10-08 20:26:17 +00:00
}
}