forge-audio 0.1.0

Zero-allocation, lock-free audio architecture for real-time DSP, game engines, and WebAssembly
Documentation
//! Stub types for modules not included in the public release.
//!
//! The core mixing architecture works without them.
//! Full implementations available under the Commercial B2B License.

use serde::{Deserialize, Serialize};

/// Stub: beat grid for tempo-synced mixing.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct BeatGrid {
    pub bpm: f64,
    pub offset_samples: i64,
    pub sample_rate: u32,
    pub beat_interval: f64,
}

impl BeatGrid {
    pub fn from_bpm(bpm: f64, offset: i64, sr: u32, _len: u32) -> Self {
        Self {
            bpm,
            offset_samples: offset,
            sample_rate: sr,
            beat_interval: 60.0 / bpm * sr as f64,
        }
    }
    pub fn beat_at_sample(&self, sample: i64) -> f64 {
        let secs = (sample - self.offset_samples) as f64 / self.sample_rate as f64;
        secs * self.bpm / 60.0
    }
    pub fn sample_at_beat(&self, beat: f64) -> i64 {
        let secs = beat * 60.0 / self.bpm;
        self.offset_samples + (secs * self.sample_rate as f64) as i64
    }
    pub fn snap_to_beat(&self, sample: i64) -> i64 {
        let beat = self.beat_at_sample(sample).round();
        self.sample_at_beat(beat)
    }
    pub fn phase_at(&self, sample: i64) -> f64 {
        let beat = self.beat_at_sample(sample);
        beat - beat.floor()
    }
}

/// Stub: effects pipeline (proprietary DSP chain).
/// Full implementation requires Commercial B2B License.
#[derive(Clone, Debug, Default)]
pub struct EffectsPipeline;
impl EffectsPipeline {
    pub fn apply(&self, _buf: &mut [f32]) {}
}

/// Stub: FX processor trait.
pub trait FxProcessor: Send {
    fn process(&mut self, buf: &mut [f32]);
    fn name(&self) -> &str;
    fn set_intensity(&mut self, _intensity: f32) {}
    fn init(&mut self, _sample_rate: u32) {}
}

/// Stub: mix bus (engine binding).
#[derive(Clone, Debug, Default)]
pub struct MixBus {
    pub deck_keys: [Option<u8>; 4],
    pub deck_bpm: [f64; 4],
    pub vocal_collision: bool,
    pub vocal_energy: f32,
}
impl MixBus {
    pub fn new() -> Self { Self::default() }
    pub fn detect_vocal(&self, _buf: &[f32]) -> f32 { 0.0 }
    pub fn update_derived(&mut self) {}
}

/// Stub: network presence hook trait.
pub trait NetworkPresenceHook: Send {
    fn on_message(&mut self, data: &[u8]);
}

/// Stub: procedural DSP module check.
pub fn is_dsp_module(_name: &str) -> bool { false }

/// Stub: procedural DSP processor creation.
pub fn create_dsp_processor(_name: &str) -> Result<Box<dyn FxProcessor>, String> {
    Err("Advanced procedural DSP modules require the Commercial B2B License — contact dev@deveraux.dev".into())
}

/// Stub: preset loading.
pub fn load_preset(_name: &str, _intensity: f32) -> Result<EffectsPipeline, String> {
    Err("Presets require the Commercial B2B License — contact dev@deveraux.dev".into())
}

/// Stub: audio command sender.
#[derive(Clone, Debug)]
pub struct AudioCommandTx;

/// Deck identifier (0-3 for a 4-deck mixer).
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DeckId(pub u8);
impl DeckId {
    pub const A: Self = Self(0);
    pub const B: Self = Self(1);
    pub const C: Self = Self(2);
    pub const D: Self = Self(3);
    pub fn as_usize(self) -> usize { self.0 as usize }
}
impl From<DeckId> for usize {
    fn from(d: DeckId) -> usize { d.0 as usize }

}

/// Sync mode for beat-matched mixing.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum SyncMode {
    #[default]
    Free,
    Leader,
    Follower,
    Off,
    BeatSync,
    BarSync,
    PhaseSync,
}

/// Minimal deck state for phase sync calculations.
#[derive(Clone, Debug, Default)]
pub struct Deck {
    pub id: DeckId,
    pub bpm: f64,
    pub playing: bool,
    pub position_samples: i64,
    pub beatgrid: Option<BeatGrid>,
    pub sync_mode: SyncMode,
}