///|
/// Timestamped events for coordinating motion, audio, and render callbacks.
pub enum MotionEventKind2 {
MarkerEvent
TriggerEvent
LoopEvent
EnterEvent
ExitEvent
} derive(Debug)
///|
pub fn motion_event_kinds2() -> Array[MotionEventKind2] {
[MarkerEvent, TriggerEvent, LoopEvent, EnterEvent, ExitEvent]
}
///|
pub struct MotionEvent2 {
time : Double
id : Int
label : String
kind : MotionEventKind2
payload : Double
consumed : Bool
} derive(Debug)
///|
pub fn motion_event2(
time : Double,
id : Int,
label : String,
kind : MotionEventKind2,
payload? : Double = 0.0,
) -> MotionEvent2 {
{ time, id, label, kind, payload, consumed: false }
}
///|
pub fn MotionEvent2::time(self : MotionEvent2) -> Double {
self.time
}
///|
pub fn MotionEvent2::id(self : MotionEvent2) -> Int {
self.id
}
///|
pub fn MotionEvent2::label(self : MotionEvent2) -> String {
self.label
}
///|
pub fn MotionEvent2::kind(self : MotionEvent2) -> MotionEventKind2 {
self.kind
}
///|
pub fn MotionEvent2::payload(self : MotionEvent2) -> Double {
self.payload
}
///|
pub fn MotionEvent2::consumed(self : MotionEvent2) -> Bool {
self.consumed
}
///|
pub fn MotionEvent2::mark_consumed(self : MotionEvent2) -> MotionEvent2 {
{
time: self.time,
id: self.id,
label: self.label,
kind: self.kind,
payload: self.payload,
consumed: true,
}
}
///|
pub struct MotionEventQueue2 {
events : Array[MotionEvent2]
mut cursor : Int
mut last_time : Double
} derive(Debug)
///|
pub fn motion_event_queue2() -> MotionEventQueue2 {
{ events: [], cursor: 0, last_time: -1000000000.0 }
}
///|
pub fn MotionEventQueue2::length(self : MotionEventQueue2) -> Int {
self.events.length()
}
///|
pub fn MotionEventQueue2::events(
self : MotionEventQueue2,
) -> Array[MotionEvent2] {
self.events.copy()
}
///|
pub fn MotionEventQueue2::cursor(self : MotionEventQueue2) -> Int {
self.cursor
}
///|
pub fn MotionEventQueue2::push(
self : MotionEventQueue2,
event : MotionEvent2,
) -> Unit {
self.events.push(event)
self.events.sort_by(fn(left, right) {
let time_order = left.time.compare(right.time)
if time_order == 0 {
left.id.compare(right.id)
} else {
time_order
}
})
}
///|
pub fn MotionEventQueue2::push_many(
self : MotionEventQueue2,
events : Array[MotionEvent2],
) -> Unit {
for event in events {
self.push(event)
}
}
///|
pub fn MotionEventQueue2::peek(self : MotionEventQueue2) -> MotionEvent2? {
if self.cursor < self.events.length() {
Some(self.events[self.cursor])
} else {
None
}
}
///|
pub fn MotionEventQueue2::poll_until(
self : MotionEventQueue2,
time : Double,
) -> Array[MotionEvent2] {
let result : Array[MotionEvent2] = []
while self.cursor < self.events.length() &&
self.events[self.cursor].time <= time {
result.push(self.events[self.cursor])
self.cursor = self.cursor + 1
}
self.last_time = time
result
}
///|
pub fn MotionEventQueue2::poll_window(
self : MotionEventQueue2,
start : Double,
end : Double,
) -> Array[MotionEvent2] {
let result : Array[MotionEvent2] = []
for event in self.events {
if event.time >= start && event.time <= end {
result.push(event)
}
}
result
}
///|
pub fn MotionEventQueue2::reset(
self : MotionEventQueue2,
time : Double,
) -> Unit {
self.cursor = 0
self.last_time = time
while self.cursor < self.events.length() &&
self.events[self.cursor].time < time {
self.cursor = self.cursor + 1
}
}
///|
pub fn MotionEventQueue2::clear(self : MotionEventQueue2) -> Unit {
self.events.clear()
self.cursor = 0
}
///|
pub struct EventWindow2 {
start : Double
end : Double
events : Array[MotionEvent2]
crossed_forward : Bool
} derive(Debug)
///|
pub fn EventWindow2::start(self : EventWindow2) -> Double {
self.start
}
///|
pub fn EventWindow2::end(self : EventWindow2) -> Double {
self.end
}
///|
pub fn EventWindow2::events(self : EventWindow2) -> Array[MotionEvent2] {
self.events.copy()
}
///|
pub fn EventWindow2::crossed_forward(self : EventWindow2) -> Bool {
self.crossed_forward
}
///|
pub fn build_event_window(
queue : MotionEventQueue2,
previous : Double,
current : Double,
) -> EventWindow2 {
let forward = current >= previous
let start = previous.min(current)
let end = previous.max(current)
{
start,
end,
events: queue.poll_window(start, end),
crossed_forward: forward,
}
}
///|
pub fn EventWindow2::contains(self : EventWindow2, time : Double) -> Bool {
time >= self.start && time <= self.end
}
///|
pub fn EventWindow2::normalized_progress(
self : EventWindow2,
time : Double,
) -> Double {
if self.end == self.start {
0.0
} else {
clamp01((time - self.start) / (self.end - self.start))
}
}
///|
pub fn filter_events_by_kind(
events : Array[MotionEvent2],
kind : MotionEventKind2,
) -> Array[MotionEvent2] {
let result : Array[MotionEvent2] = []
for event in events {
let matches = match (event.kind, kind) {
(MarkerEvent, MarkerEvent)
| (TriggerEvent, TriggerEvent)
| (LoopEvent, LoopEvent)
| (EnterEvent, EnterEvent)
| (ExitEvent, ExitEvent) => true
(_, _) => false
}
if matches {
result.push(event)
}
}
result
}
///|
pub fn event_times(events : Array[MotionEvent2]) -> Array[Double] {
let result : Array[Double] = []
for event in events {
result.push(event.time)
}
result
}
///|
pub fn next_event_time(events : Array[MotionEvent2], after : Double) -> Double? {
let mut best : Double? = None
for event in events {
if event.time > after {
match best {
None => best = Some(event.time)
Some(value) => if event.time < value { best = Some(event.time) }
}
}
}
best
}
///|
pub fn event_queue_duration(queue : MotionEventQueue2) -> Double {
if queue.events.length() < 2 {
return 0.0
}
queue.events[queue.events.length() - 1].time - queue.events[0].time
}