use serde::{Deserialize, Serialize};
#[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()
}
}
#[derive(Clone, Debug, Default)]
pub struct EffectsPipeline;
impl EffectsPipeline {
pub fn apply(&self, _buf: &mut [f32]) {}
}
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) {}
}
#[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) {}
}
pub trait NetworkPresenceHook: Send {
fn on_message(&mut self, data: &[u8]);
}
pub fn is_dsp_module(_name: &str) -> bool { false }
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())
}
pub fn load_preset(_name: &str, _intensity: f32) -> Result<EffectsPipeline, String> {
Err("Presets require the Commercial B2B License — contact dev@deveraux.dev".into())
}
#[derive(Clone, Debug)]
pub struct AudioCommandTx;
#[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 }
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum SyncMode {
#[default]
Free,
Leader,
Follower,
Off,
BeatSync,
BarSync,
PhaseSync,
}
#[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,
}