pub mod random;
pub mod shapes;
pub mod transformers;
use std::{
collections::HashMap,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
},
time::{Duration, Instant},
};
use buttplug::client::{ButtplugClient, ButtplugClientError, ScalarValueCommand};
use tokio::time::interval;
use transformers::*;
pub trait PatternGenerator {
fn sample(&mut self, time: Duration) -> f64;
fn duration(&self) -> Duration;
fn reset(&mut self) {}
}
impl<T: PatternGenerator> Pattern for T {}
pub trait Pattern: PatternGenerator + Sized {
fn scale_time(self, scalar: f64) -> ScaleTime<Self> {
ScaleTime {
pattern: self,
scalar,
}
}
fn scale_intensity(self, scalar: f64) -> ScaleIntensity<Self> {
ScaleIntensity {
pattern: self,
scalar,
}
}
fn sum<Q: Pattern>(self, other: Q) -> Sum<Self, Q> {
Sum { a: self, b: other }
}
fn subtract<Q: Pattern>(self, other: Q) -> Subtract<Self, Q> {
Subtract { a: self, b: other }
}
fn average<Q: Pattern>(self, other: Q) -> Average<Self, Q> {
Average { a: self, b: other }
}
fn clamp(self, floor: f64, ceiling: f64) -> Clamp<Self> {
Clamp {
pattern: self,
floor,
ceiling,
}
}
fn clamp_valid(self) -> Clamp<Self> {
self.clamp(0.0, 1.0)
}
fn scale_valid(self) -> ValidScale<Self> {
ValidScale { pattern: self }
}
fn shift(self, time_shift: f64) -> Shift<Self> {
Shift {
pattern: self,
time_shift,
}
}
fn repeat(self, count: f64) -> Repeat<Self> {
Repeat {
pattern: self,
count,
}
}
fn forever(self) -> Forever<Self> {
Forever { pattern: self }
}
fn chain<Q: Pattern>(self, other: Q) -> Chain<Self, Q> {
Chain {
first: self,
then: other,
}
}
fn multiply<M: Pattern>(self, modulator: M) -> AmplitudeModulator<Self, M> {
AmplitudeModulator {
pattern: self,
modulator,
}
}
}
pub struct CustomPattern {
pub sample: fn(Duration) -> f64,
pub duration: fn() -> Duration,
}
impl PatternGenerator for CustomPattern {
fn sample(&mut self, time: Duration) -> f64 {
(self.sample)(time)
}
fn duration(&self) -> Duration {
(self.duration)()
}
}
pub struct Driver {
pub buttplug: Arc<ButtplugClient>,
tickrate_hz: u64,
pattern: Box<dyn PatternGenerator>,
device_patterns: HashMap<u32, Box<dyn PatternGenerator>>,
actuator_patterns: HashMap<(u32, u32), Box<dyn PatternGenerator>>,
}
impl Driver {
pub fn new<P: 'static + Pattern>(bp: Arc<ButtplugClient>, pattern: P) -> Self {
Driver {
buttplug: bp,
tickrate_hz: 10, pattern: Box::new(pattern),
device_patterns: HashMap::new(),
actuator_patterns: HashMap::new(),
}
}
pub fn set_tickrate(&mut self, hz: u64) -> &mut Self {
self.tickrate_hz = hz;
self
}
pub fn set_pattern<P: 'static + PatternGenerator>(&mut self, pattern: P) -> &mut Self {
self.pattern = Box::new(pattern);
self
}
pub fn set_device_pattern<P: 'static + PatternGenerator>(
&mut self,
device_id: u32,
pattern: P,
) -> &mut Self {
self.device_patterns.insert(device_id, Box::new(pattern));
self
}
pub fn remove_device_pattern(&mut self, device_id: u32) -> &mut Self {
self.device_patterns.remove(&device_id);
self
}
pub fn set_actuator_pattern<P: 'static + PatternGenerator>(
&mut self,
device_id: u32,
actuator_id: u32,
pattern: P,
) -> &mut Self {
self.actuator_patterns
.insert((device_id, actuator_id), Box::new(pattern));
self
}
pub fn remove_actuator_pattern(&mut self, device_id: u32, actuator_id: u32) -> &mut Self {
self.actuator_patterns.remove(&(device_id, actuator_id));
self
}
pub async fn run(&mut self) -> Result<(), ButtplugClientError> {
self.run_while(AtomicBool::new(true)).await
}
pub async fn run_while(&mut self, running: AtomicBool) -> Result<(), ButtplugClientError> {
self.pattern.reset();
self.device_patterns.values_mut().for_each(|p| p.reset());
self.actuator_patterns.values_mut().for_each(|p| p.reset());
let start = Instant::now();
let mut interval = interval(Duration::from_millis(1000 / self.tickrate_hz));
while running.load(Ordering::Acquire) {
let elapsed = start.elapsed();
if elapsed > self.pattern.duration() {
break;
}
let global_intensity = self.pattern.sample(elapsed);
for device in self.buttplug.devices() {
let mut actuator_map: HashMap<u32, f64> = HashMap::new();
for actuator in device.vibrate_attributes() {
let level = self
.actuator_patterns
.get_mut(&(device.index(), *actuator.index()))
.map(|p| p.sample(elapsed))
.unwrap_or(
self.device_patterns
.get_mut(&device.index())
.map(|p| p.sample(elapsed))
.unwrap_or(global_intensity),
);
actuator_map.insert(*actuator.index(), level);
}
device
.vibrate(&ScalarValueCommand::ScalarValueMap(actuator_map))
.await?;
}
interval.tick().await;
}
self.buttplug.stop_all_devices().await
}
}