rocket_sync/
lib.rs

1#![no_std]
2
3extern crate smallvec;
4use smallvec::SmallVec;
5
6pub struct SyncDevice {
7    /// sync tracks (the vertical columns in the editor)
8    pub tracks: SmallVec<[SyncTrack; 64]>,
9    /// rows per beat
10    pub rpb: u8,
11    /// beats per minute
12    pub bpm: f64,
13    /// rows per second
14    pub rps: f64,
15    pub is_paused: bool,
16    /// current row
17    pub row: u32,
18    /// current time in milliseconds
19    pub time: u32,
20}
21
22impl SyncDevice {
23    pub fn new(bpm: f64, rpb: u8) -> SyncDevice {
24        SyncDevice {
25            tracks: SmallVec::new(),
26            rpb: rpb,
27            bpm: bpm,
28            rps: rps(bpm, rpb),
29            is_paused: true,
30            row: 0,
31            time: 0,
32        }
33    }
34
35    pub fn set_row_from_time(&mut self) {
36        let r: f64 = (self.time as f64 / 1000.0) * self.rps + 0.5;
37        self.row = r as u32;
38    }
39
40    pub fn get_track_value(&self, track_id: usize) -> Result<f64, SyncError> {
41        if self.tracks.len() > track_id {
42            return Ok(self.tracks[track_id].value_at(self.row));
43        } else {
44            return Err(SyncError::TrackDoesntExist);
45        }
46    }
47}
48
49pub struct SyncTrack {
50    /// key frames, rows where values change
51    pub keys: SmallVec<[TrackKey; 64]>,
52}
53
54pub enum SyncError {
55    TrackDoesntExist
56}
57
58pub struct TrackKey {
59    pub row: u32,
60    pub value: f32,
61    /// interpolation type
62    pub key_type: KeyType,
63}
64
65pub enum KeyType {
66    Step, // constant until value changes
67    Linear, // linear interpolation
68    Smooth, // smooth curve
69    Ramp, // exponential ramp
70    NOOP,
71}
72
73pub enum ActiveKeyIdx {
74    /// key is on this row
75    ExactRow(usize),
76    /// key is on a previous row
77    PrevRow(usize),
78    /// the row is before the first key
79    BeforeFirstRow,
80    /// row moved past the last row
81    AfterLastRow,
82}
83
84impl SyncTrack {
85    pub fn new() -> SyncTrack {
86        SyncTrack {
87            keys: SmallVec::new(),
88        }
89    }
90
91    /// Adds a key to the track, inserting sorted by row, replacing if one already exists on that row
92    pub fn add_key(&mut self, track_key: TrackKey) {
93
94        let res = self.find_active_key_idx_for_row(track_key.row);
95
96        if let Some(idx) = res {
97            // Some kind of active key
98            use self::ActiveKeyIdx::*;
99            match idx {
100                // replace key
101                ExactRow(n) => self.keys[n] = track_key,
102
103                // add new key
104                PrevRow(n) => self.keys.insert(n+1, track_key),
105                BeforeFirstRow => self.keys.insert(0, track_key),
106                AfterLastRow => self.keys.push(track_key),
107            }
108        } else {
109            // No keys, first key
110            self.keys.push(track_key);
111        }
112    }
113
114    /// Deletes the key found on the given row
115    pub fn delete_key(&mut self, row: u32) {
116        if let Some(idx) = self.find_key_idx_by_row(row) {
117            self.keys.remove(idx);
118        }
119    }
120
121    /// Returns index of the key with the given row, or `None`
122    pub fn find_key_idx_by_row(&self, row: u32) -> Option<usize> {
123        for (idx, key) in self.keys.iter().enumerate() {
124            if key.row == row {
125                return Some(idx);
126            }
127        }
128
129        None
130    }
131
132    pub fn value_at(&self, row: u32) -> f64 {
133
134        let hit_idx: usize;
135
136        if let Some(hit) = self.find_active_key_idx_for_row(row) {
137            use self::ActiveKeyIdx::*;
138            match hit {
139                ExactRow(n) => return self.keys[n].value as f64,
140
141                PrevRow(n) => hit_idx = n,
142
143                // hit is beyond the last key
144                AfterLastRow => return self.keys[self.keys.len() - 1].value as f64,
145
146                BeforeFirstRow => return self.keys[0].value as f64,
147            }
148        } else {
149            return 0.0;
150        }
151
152        // return interpolated value
153        let cur_key = &self.keys[hit_idx];
154        let next_key = &self.keys[hit_idx + 1];
155
156	      let t: f64 = ((row - cur_key.row) as f64) / ((next_key.row - cur_key.row) as f64);
157        let a: f64 = cur_key.value as f64;
158        let b: f64 = (next_key.value - cur_key.value) as f64;
159
160        use self::KeyType::*;
161        match cur_key.key_type {
162            Step => return a,
163
164            Linear => return a + b * t,
165
166            Smooth => return a + b * (t*t * (3.0 - 2.0 * t)),
167
168            Ramp => return a + b * t*t,
169
170            NOOP => return 0.0,
171        }
172
173    }
174
175    /// Find the active key idx for a row
176    pub fn find_active_key_idx_for_row(&self, row: u32) -> Option<ActiveKeyIdx> {
177        if self.keys.len() == 0 {
178            return None;
179        }
180
181        // Linear search. Keys are sorted by row.
182
183        let mut hit_idx: usize = 0;
184        let mut ret: Option<ActiveKeyIdx> = None;
185
186        for (idx, key) in self.keys.iter().enumerate() {
187            if key.row == row {
188                return Some(ActiveKeyIdx::ExactRow(idx));
189            } else if key.row < row {
190                hit_idx = idx;
191                ret = Some(ActiveKeyIdx::PrevRow(hit_idx));
192            }
193        }
194
195        if hit_idx == self.keys.len() - 1 {
196            return Some(ActiveKeyIdx::AfterLastRow);
197        }
198
199        if hit_idx == 0 && ret.is_none() {
200            return Some(ActiveKeyIdx::BeforeFirstRow);
201        }
202
203        ret
204    }
205}
206
207impl TrackKey {
208    pub fn new() -> TrackKey {
209        TrackKey {
210            row: 0,
211            value: 0.0,
212            key_type: KeyType::Step,
213        }
214    }
215}
216
217/// Calculate rows per second
218pub fn rps(bpm: f64, rpb: u8) -> f64 {
219    (bpm / 60.0) * (rpb as f64)
220}
221
222pub fn key_to_code(key: &KeyType) -> u8 {
223    use self::KeyType::*;
224    match *key {
225        Step      => 0,
226        Linear    => 1,
227        Smooth    => 2,
228        Ramp      => 3,
229        NOOP      => 255,
230    }
231}
232
233pub fn code_to_key(code: u8) -> KeyType {
234    use self::KeyType::*;
235    match code {
236        0 => Step,
237        1 => Linear,
238        2 => Smooth,
239        3 => Ramp,
240        _ => NOOP,
241    }
242}