1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
4#[serde(rename_all = "lowercase")]
5pub enum DeckId { A, B }
6
7impl DeckId {
8 pub const ALL: [Self; 2] = [Self::A, Self::B];
9 pub const fn index(self) -> usize { match self { Self::A => 0, Self::B => 1 } }
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum LoadStatus { Empty, Loading, Ready, Failed }
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "snake_case")]
18pub enum SurfaceRegion { Programme, LeadIn, Deadwax }
19
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub struct PlaybackState {
22 pub load_status: LoadStatus,
23 pub duration_seconds: f64,
24 pub current_seconds: f64,
25 pub playing: bool,
26 pub pending_play_when_ready: bool,
27 pub suspended_at_seconds: Option<f64>,
28 pub playback_rate: f32,
29}
30
31impl Default for PlaybackState {
32 fn default() -> Self {
33 Self { load_status: LoadStatus::Empty, duration_seconds: 0.0, current_seconds: 0.0, playing: false, pending_play_when_ready: false, suspended_at_seconds: None, playback_rate: 1.0 }
34 }
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
38pub struct TransportState { pub motor_on: bool }
39impl Default for TransportState { fn default() -> Self { Self { motor_on: false } } }
40
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42pub struct NeedleState { pub lifted: bool }
43impl Default for NeedleState { fn default() -> Self { Self { lifted: true } } }
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub struct MixerState {
47 pub channel_gain: f32,
48 pub crossfader: f32,
49}
50impl Default for MixerState { fn default() -> Self { Self { channel_gain: 1.0, crossfader: 0.5 } } }
51
52#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
53pub struct ScratchState {
54 pub active: bool,
55 pub pointer_id: Option<i32>,
56 pub was_playing: bool,
57 pub started_at_seconds: f64,
58 pub target_position_frames: f64,
59 pub rendered_position_frames: f64,
60 pub target_rate: f32,
61 pub base_rotation_degrees: f64,
62}
63impl Default for ScratchState {
64 fn default() -> Self { Self { active: false, pointer_id: None, was_playing: false, started_at_seconds: 0.0, target_position_frames: 0.0, rendered_position_frames: 0.0, target_rate: 0.0, base_rotation_degrees: 0.0 } }
65}
66
67#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
68pub struct DeckState {
69 pub loaded: bool,
70 pub transport: TransportState,
71 pub needle: NeedleState,
72 pub playback: PlaybackState,
73 pub mixer: MixerState,
74 pub scratch: ScratchState,
75}
76impl Default for DeckState {
77 fn default() -> Self { Self { loaded: false, transport: TransportState::default(), needle: NeedleState::default(), playback: PlaybackState::default(), mixer: MixerState::default(), scratch: ScratchState::default() } }
78}
79
80#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
81pub struct TimedRegionState {
82 pub active: bool,
83 pub completed: bool,
84 pub started_at_ms: f64,
85 pub duration_ms: f64,
86}
87impl Default for TimedRegionState {
88 fn default() -> Self { Self { active: false, completed: false, started_at_ms: 0.0, duration_ms: 0.0 } }
89}
90
91#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
92pub struct ClipLoopState { pub active: bool, pub clip_id: Option<String> }
93impl Default for ClipLoopState { fn default() -> Self { Self { active: false, clip_id: None } } }
94
95#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
96pub struct PlayerConfig {
97 pub sample_rate: f64,
98 pub sharp_crossfader_width: f32,
99}
100impl Default for PlayerConfig { fn default() -> Self { Self { sample_rate: 48_000.0, sharp_crossfader_width: 0.08 } } }
101
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
103pub struct PlayerState {
104 pub decks: [DeckState; 2],
105 pub active_deck: DeckId,
106 pub lead_in: TimedRegionState,
107 pub deadwax: TimedRegionState,
108 pub clip_loop: ClipLoopState,
109}
110impl Default for PlayerState {
111 fn default() -> Self { Self { decks: [DeckState::default(), DeckState::default()], active_deck: DeckId::A, lead_in: TimedRegionState::default(), deadwax: TimedRegionState::default(), clip_loop: ClipLoopState::default() } }
112}