notation_audio 0.6.0

Fun notation - audio features
Documentation
use bevy::prelude::*;
use bevy::audio::{Source, AddAudioSource};
use ringbuffer::{AllocRingBuffer, RingBuffer};
use bevy::utils::syncunsafecell::SyncUnsafeCell;
use std::sync::Arc;

pub struct MonoStreamDecoder {
    buffer: Arc<SyncUnsafeCell<AllocRingBuffer<f32>>>,
}

impl std::fmt::Debug for MonoStreamDecoder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let buffer = unsafe {
            self.buffer.as_ref().get().as_mut().unwrap()
        };
        write!(f, "<MonoStreamDecoder>({}/{})", buffer.len(), buffer.capacity())
    }
}

impl Iterator for MonoStreamDecoder {
    type Item = f32;

    fn next(&mut self) -> Option<Self::Item> {
        let buffer = unsafe {
            self.buffer.as_ref().get().as_mut().unwrap()
        };
        if buffer.is_full() {
            let capacity = buffer.capacity();
            println!("<MonoStreamDecoder>[{}] buffer is full", capacity);
        }
        let data = buffer.dequeue().unwrap_or(0.0);
        Some(data)
    }
}

impl Source for MonoStreamDecoder {
    fn current_frame_len(&self) -> Option<usize> {
        None
    }

    fn channels(&self) -> u16 {
        1
    }

    fn sample_rate(&self) -> u32 {
        44_100
    }

    fn total_duration(&self) -> Option<std::time::Duration> {
        None
    }
}

#[derive(Asset, TypePath)]
pub struct MonoStream {
    pub volume: f32,
    buffer: Arc<SyncUnsafeCell<AllocRingBuffer<f32>>>,
}

impl std::fmt::Debug for MonoStream {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let buffer = unsafe {
            self.buffer.as_ref().get().as_mut().unwrap()
        };
        write!(f, "<MonoStream>({}/{}, v:{})", buffer.len(), buffer.capacity(), self.volume)
    }
}

impl Decodable for MonoStream {
    type DecoderItem = <MonoStreamDecoder as Iterator>::Item;
    type Decoder = MonoStreamDecoder;

    fn decoder(&self) -> Self::Decoder {
        MonoStreamDecoder {
            buffer: self.buffer.clone(),
        }
    }
}

impl MonoStream {
    pub const FRAME_STEP: f64 = 1.0 / 44_100.0;

    pub const DEFAULT_CAPACITY: usize = 4096;
    pub const DEFAULT_VOLUME: f32 = 1.0;

    pub fn remaining(&self) -> usize {
        let buffer = unsafe {
            self.buffer.as_ref().get().as_mut().unwrap()
        };
        buffer.capacity() - buffer.len()
    }

    pub fn push(&mut self, data: f32) {
        let buffer = unsafe {
            self.buffer.as_ref().get().as_mut().unwrap()
        };
        buffer.push(data * self.volume);
    }

    pub fn push_batch(&mut self, volume_factor: f32, data: &[f32]) {
        let buffer = unsafe {
            self.buffer.as_ref().get().as_mut().unwrap()
        };
        for i in 0..data.len() {
            buffer.push(data[i] * self.volume * volume_factor);
        }
    }

    pub fn init_streaming(
        app: &mut App,
        setup_default_streaming: bool,
    ) {
        app.add_audio_source::<MonoStream>();
        if setup_default_streaming {
            app.add_systems(Startup, Self::setup_default_streaming);
        }
    }
    pub fn setup_streaming(
        commands: &mut Commands,
        assets: &mut ResMut<Assets<MonoStream>>,
        capacity: usize,
        volume: f32,
    ) {
        let buffer = AllocRingBuffer::<f32>::new(capacity);
        let stream = MonoStream {
            volume,
            buffer: Arc::new(SyncUnsafeCell::new(buffer)),
        };
        let stream_handle = assets.add(stream);
        commands.spawn(AudioSourceBundle {
            source: stream_handle,
            ..default()
        });
    }
    pub fn setup_default_streaming(
        mut commands: Commands,
        mut assets: ResMut<Assets<MonoStream>>,
    ) {
        Self::setup_streaming(&mut commands, &mut assets, Self::DEFAULT_CAPACITY, Self::DEFAULT_VOLUME);
    }
}