Last active
February 25, 2020 18:03
-
-
Save andresilva/ea9b6d4923c76148058cea7846fb43ab to your computer and use it in GitHub Desktop.
Motivational USB foot pedal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "motivation-pedal" | |
version = "0.1.0" | |
authors = ["André Silva <[email protected]>"] | |
edition = "2018" | |
[dependencies] | |
env_logger = "0.7.1" | |
hidapi = "1.1.1" | |
log = "0.4.8" | |
rand = "0.7.0" | |
rodio = "0.10.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::VecDeque; | |
const VID: u16 = 0x0c45; | |
const PID: u16 = 0x7404; | |
fn pressed(buf: &[u8; 8]) -> bool { | |
*buf == [1, 0, 0, 5, 0, 0, 0, 0] | |
} | |
fn random_motivational<'a>(previous: Option<&mut VecDeque<usize>>) -> (&'a str, &'a [u8]) { | |
use rand::Rng; | |
macro_rules! sound { | |
($x:expr) => { | |
($x, include_bytes!(concat!("../sounds/", $x))) | |
}; | |
} | |
const SOUNDS: &[(&str, &[u8])] = &[ | |
sound!("do_it.ogg"), | |
sound!("dreams2.ogg"), | |
sound!("dreams.ogg"), | |
sound!("give_up.ogg"), | |
sound!("impossible.ogg"), | |
sound!("just_do_it.ogg"), | |
sound!("quit.ogg"), | |
sound!("tomorrow.ogg"), | |
sound!("waiting.ogg"), | |
sound!("work.ogg"), | |
sound!("yes.ogg"), | |
]; | |
const PREVIOUS_N: usize = 4; | |
let mut rng = rand::thread_rng(); | |
let index = loop { | |
let index = rng.gen_range(0, SOUNDS.len()); | |
match previous { | |
Some(previous) if !previous.contains(&index) => { | |
while previous.len() >= PREVIOUS_N { | |
previous.pop_front(); | |
} | |
previous.push_back(index); | |
break index; | |
} | |
None => break index, | |
_ => {} | |
} | |
}; | |
SOUNDS[index] | |
} | |
fn play_random_motivational( | |
device: &rodio::Device, | |
previous: Option<&mut VecDeque<usize>>, | |
) -> Result<rodio::Sink, String> { | |
use std::io::Cursor; | |
let (name, data) = random_motivational(previous); | |
let source = Cursor::new(data); | |
log::info!("playing: {}", name); | |
rodio::play_once(device, source).map_err(|err| err.to_string()) | |
} | |
fn main() -> Result<(), String> { | |
env_logger::builder() | |
.filter_level(log::LevelFilter::Info) | |
.init(); | |
let hid_api = hidapi::HidApi::new().map_err(|err| err.to_string())?; | |
let usb_device = hid_api.open(VID, PID).map_err(|err| err.to_string())?; | |
let audio_device = rodio::default_output_device().ok_or("No audio device found.")?; | |
let mut _audio_sink; | |
let mut previous = VecDeque::new(); | |
let mut buf = [0u8; 8]; | |
loop { | |
// blocks until the pedal is pressed/released | |
let n = usb_device | |
.read(&mut buf[..]) | |
.map_err(|err| err.to_string())?; | |
assert_eq!(n, 8); | |
if pressed(&buf) { | |
// if the sink is dropped playback stops | |
_audio_sink = play_random_motivational(&audio_device, Some(&mut previous)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment