2021-12-12 23:20:09 +00:00
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
use std::sync::{Arc, Mutex, MutexGuard};
|
2024-02-24 21:02:09 +00:00
|
|
|
use femtos::{Instant, Duration};
|
2021-12-12 23:20:09 +00:00
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
use moa_core::host::{Audio, Sample, AudioFrame, ClockedQueue};
|
2021-12-12 23:20:09 +00:00
|
|
|
|
|
|
|
|
2023-03-15 03:05:29 +00:00
|
|
|
pub const SAMPLE_RATE: usize = 48000;
|
2021-12-12 23:20:09 +00:00
|
|
|
|
|
|
|
pub struct AudioSource {
|
2022-10-08 20:26:17 +00:00
|
|
|
id: usize,
|
2021-12-12 23:20:09 +00:00
|
|
|
sample_rate: usize,
|
2022-10-08 20:26:17 +00:00
|
|
|
queue: ClockedQueue<AudioFrame>,
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AudioSource {
|
2023-05-07 17:03:25 +00:00
|
|
|
// 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 {
|
2023-05-06 17:04:44 +00:00
|
|
|
let queue = ClockedQueue::new(5000);
|
2023-05-07 17:03:25 +00:00
|
|
|
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(),
|
|
|
|
)
|
|
|
|
};
|
2021-12-12 23:20:09 +00:00
|
|
|
|
|
|
|
Self {
|
2022-10-08 20:26:17 +00:00
|
|
|
id,
|
2021-12-12 23:20:09 +00:00
|
|
|
sample_rate,
|
2022-10-08 20:26:17 +00:00
|
|
|
queue,
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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]) {
|
2023-05-07 17:03:25 +00:00
|
|
|
let mut data = Vec::with_capacity(buffer.len());
|
2022-10-08 23:17:17 +00:00
|
|
|
for sample in buffer.iter() {
|
2023-05-07 17:03:25 +00:00
|
|
|
data.push(*sample);
|
2022-10-08 23:17:17 +00:00
|
|
|
}
|
2022-10-08 20:26:17 +00:00
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
let frame = AudioFrame::new(self.sample_rate, data);
|
2022-10-08 20:26:17 +00:00
|
|
|
|
|
|
|
self.queue.push(clock, frame);
|
|
|
|
}
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 20:26:17 +00:00
|
|
|
|
2021-12-12 23:20:09 +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);
|
2022-01-26 19:12:09 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-12 23:20:09 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
2023-05-07 17:03:25 +00:00
|
|
|
pub struct AudioMixer(Arc<Mutex<AudioMixerInner>>);
|
|
|
|
|
|
|
|
pub struct AudioMixerInner {
|
2021-12-12 23:20:09 +00:00
|
|
|
sample_rate: usize,
|
2022-10-08 20:26:17 +00:00
|
|
|
sources: Vec<ClockedQueue<AudioFrame>>,
|
2023-05-07 17:03:25 +00:00
|
|
|
output: AudioOutput,
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl AudioMixer {
|
2023-05-07 17:03:25 +00:00
|
|
|
pub fn new(sample_rate: usize) -> AudioMixer {
|
|
|
|
AudioMixer(Arc::new(Mutex::new(AudioMixerInner {
|
2021-12-12 23:20:09 +00:00
|
|
|
sample_rate,
|
2022-10-08 20:26:17 +00:00
|
|
|
sources: vec![],
|
2023-05-08 03:42:55 +00:00
|
|
|
output: AudioOutput::default(),
|
2023-05-07 17:03:25 +00:00
|
|
|
})))
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
pub fn with_default_rate() -> AudioMixer {
|
2021-12-12 23:20:09 +00:00
|
|
|
AudioMixer::new(SAMPLE_RATE)
|
|
|
|
}
|
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-05-06 17:04:44 +00:00
|
|
|
pub fn num_sources(&self) -> usize {
|
|
|
|
self.sources.len()
|
|
|
|
}
|
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
pub fn get_sink(&mut self) -> AudioOutput {
|
2022-10-08 20:26:17 +00:00
|
|
|
self.output.clone()
|
|
|
|
}
|
|
|
|
|
2021-12-12 23:20:09 +00:00
|
|
|
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) {
|
2023-05-07 17:03:25 +00:00
|
|
|
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
|
|
|
|
2023-05-07 17:03:25 +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
|
|
|
}
|
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
self.output.add_frame(frame_start, AudioFrame::new(self.sample_rate, data));
|
|
|
|
}
|
|
|
|
}
|
2022-10-08 20:26:17 +00:00
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
use moa_core::{Transmutable, Steppable, Error, System};
|
2022-10-08 20:26:17 +00:00
|
|
|
|
2023-05-07 17:03:25 +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);
|
2023-05-07 17:03:25 +00:00
|
|
|
// 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
|
|
|
}
|
2023-05-07 17:03:25 +00:00
|
|
|
Ok(duration)
|
|
|
|
}
|
|
|
|
}
|
2022-10-08 20:26:17 +00:00
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
impl Transmutable for AudioMixer {
|
|
|
|
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
|
|
|
Some(self)
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-07 17:03:25 +00:00
|
|
|
|
|
|
|
// TODO this should be split up into a sender/receiver
|
|
|
|
#[derive(Clone)]
|
2021-12-12 23:20:09 +00:00
|
|
|
pub struct AudioOutput {
|
2023-05-07 17:03:25 +00:00
|
|
|
queue: ClockedQueue<AudioFrame>,
|
2021-12-12 23:20:09 +00:00
|
|
|
}
|
|
|
|
|
2023-05-08 03:42:55 +00:00
|
|
|
impl Default for AudioOutput {
|
|
|
|
fn default() -> Self {
|
2023-05-07 17:03:25 +00:00
|
|
|
Self {
|
|
|
|
queue: ClockedQueue::new(5000),
|
|
|
|
}
|
2023-03-15 03:05:29 +00:00
|
|
|
}
|
2023-05-08 03:42:55 +00:00
|
|
|
}
|
2023-03-15 03:05:29 +00:00
|
|
|
|
2023-05-08 03:42:55 +00:00
|
|
|
impl AudioOutput {
|
2024-02-24 21:02:09 +00:00
|
|
|
pub fn add_frame(&self, clock: Instant, frame: AudioFrame) {
|
2023-05-07 17:03:25 +00:00
|
|
|
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) {
|
2023-05-07 17:03:25 +00:00
|
|
|
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)> {
|
2023-05-07 17:03:25 +00:00
|
|
|
self.queue.pop_next()
|
2022-10-08 20:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
2023-05-07 17:03:25 +00:00
|
|
|
self.queue.is_empty()
|
2022-10-08 20:26:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|