1use serde::{Deserialize, Serialize};
2
3use crate::mixer::DEFAULT_SHARP_CROSSFADER_WIDTH;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum DeckId {
8 A,
9 B,
10}
11
12impl DeckId {
13 pub const ALL: [Self; 2] = [Self::A, Self::B];
14 pub const fn index(self) -> usize {
15 match self {
16 Self::A => 0,
17 Self::B => 1,
18 }
19 }
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum LoadStatus {
25 Empty,
26 Loading,
27 Ready,
28 Failed,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum SurfaceRegion {
34 Programme,
35 LeadIn,
36 Deadwax,
37}
38
39#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
40pub struct PlaybackState {
41 pub load_status: LoadStatus,
42 pub duration_seconds: f64,
43 pub current_seconds: f64,
44 pub source_sample_rate: f64,
47 pub playing: bool,
48 pub pending_play_when_ready: bool,
49 pub suspended_at_seconds: Option<f64>,
50 pub playback_rate: f32,
51}
52
53impl Default for PlaybackState {
54 fn default() -> Self {
55 Self {
56 load_status: LoadStatus::Empty,
57 duration_seconds: 0.0,
58 current_seconds: 0.0,
59 source_sample_rate: 48_000.0,
60 playing: false,
61 pending_play_when_ready: false,
62 suspended_at_seconds: None,
63 playback_rate: 1.0,
64 }
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
69pub struct TransportState {
70 pub motor_on: bool,
71}
72impl Default for TransportState {
73 fn default() -> Self {
74 Self { motor_on: false }
75 }
76}
77
78#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79pub struct NeedleState {
80 pub lifted: bool,
81}
82impl Default for NeedleState {
83 fn default() -> Self {
84 Self { lifted: true }
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
89pub struct MixerState {
90 pub channel_gain: f32,
91 pub crossfader: f32,
92}
93impl Default for MixerState {
94 fn default() -> Self {
95 Self {
96 channel_gain: 1.0,
97 crossfader: 0.5,
98 }
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
103pub struct ScratchState {
104 pub active: bool,
105 pub pointer_id: Option<i32>,
106 pub was_playing: bool,
107 pub started_at_seconds: f64,
108 pub target_position_frames: f64,
109 pub rendered_position_frames: f64,
110 pub target_rate: f32,
111 pub grip: f32,
112 pub base_rotation_degrees: f64,
113}
114impl Default for ScratchState {
115 fn default() -> Self {
116 Self {
117 active: false,
118 pointer_id: None,
119 was_playing: false,
120 started_at_seconds: 0.0,
121 target_position_frames: 0.0,
122 rendered_position_frames: 0.0,
123 target_rate: 0.0,
124 grip: 0.0,
125 base_rotation_degrees: 0.0,
126 }
127 }
128}
129
130#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
131pub struct DeckState {
132 pub loaded: bool,
133 pub transport: TransportState,
134 pub needle: NeedleState,
135 pub playback: PlaybackState,
136 pub mixer: MixerState,
137 pub scratch: ScratchState,
138}
139impl Default for DeckState {
140 fn default() -> Self {
141 Self {
142 loaded: false,
143 transport: TransportState::default(),
144 needle: NeedleState::default(),
145 playback: PlaybackState::default(),
146 mixer: MixerState::default(),
147 scratch: ScratchState::default(),
148 }
149 }
150}
151
152#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
153pub struct TimedRegionState {
154 pub active: bool,
155 pub completed: bool,
156 pub started_at_ms: f64,
157 pub duration_ms: f64,
158}
159impl Default for TimedRegionState {
160 fn default() -> Self {
161 Self {
162 active: false,
163 completed: false,
164 started_at_ms: 0.0,
165 duration_ms: 0.0,
166 }
167 }
168}
169
170#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
171pub struct ClipLoopState {
172 pub active: bool,
173 pub clip_id: Option<String>,
174}
175impl Default for ClipLoopState {
176 fn default() -> Self {
177 Self {
178 active: false,
179 clip_id: None,
180 }
181 }
182}
183
184#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
185pub struct PlayerConfig {
186 pub sample_rate: f64,
187 pub sharp_crossfader_width: f32,
188}
189impl Default for PlayerConfig {
190 fn default() -> Self {
191 Self {
192 sample_rate: 48_000.0,
193 sharp_crossfader_width: DEFAULT_SHARP_CROSSFADER_WIDTH,
194 }
195 }
196}
197
198#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
199pub struct PlayerState {
200 pub decks: [DeckState; 2],
201 pub active_deck: DeckId,
202 pub lead_in: TimedRegionState,
203 pub deadwax: TimedRegionState,
204 pub clip_loop: ClipLoopState,
205}
206impl Default for PlayerState {
207 fn default() -> Self {
208 Self {
209 decks: [DeckState::default(), DeckState::default()],
210 active_deck: DeckId::A,
211 lead_in: TimedRegionState::default(),
212 deadwax: TimedRegionState::default(),
213 clip_loop: ClipLoopState::default(),
214 }
215 }
216}