From 5ffe22ce17d75ff551338f70dd3f7f52111d9e26 Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Tue, 20 Oct 2020 11:53:36 +0200 Subject: [PATCH] initial working version --- .gitignore | 1 + Cargo.toml | 14 +++++ src/main.rs | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..55c6363 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "waagner" +version = "0.1.0" +authors = ["_ <_@_>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serial = "*" +rodio = "0.12" +walkdir = "*" +rand = { version = "*", features = ["small_rng"] } + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5155b3c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,146 @@ +use serial::SerialPort; + +use walkdir::WalkDir; +fn main() { + let helptext = "Argument 1 is serial port (for example /dev/ttyACM0, Argument 2 is the directory with the music, no stars."; + let mut args = std::env::args_os(); + let _selfname = args.next(); + let serialport = args.next().expect(helptext); + let musicdir = args.next().expect(helptext); + + println!("opening serial port"); + + let mut port = serial::open(&serialport).expect("could not open serial port"); + port.reconfigure(&|settings| { + settings.set_baud_rate(serial::Baud115200)?; + settings.set_char_size(serial::Bits8); + settings.set_parity(serial::ParityNone); + settings.set_stop_bits(serial::Stop1); + settings.set_flow_control(serial::FlowNone); + Ok(()) + }) + .expect("could not configure port"); + port.set_timeout(std::time::Duration::from_secs(30)) + .expect("could not set timeout"); + + println!("serial port opened"); + + println!("skimming music dir"); + + let walker = WalkDir::new(musicdir).into_iter(); + let walker = walker.filter_entry(|e| { + e.file_name() + .to_str() + .map(|s| !s.starts_with('.')) + .unwrap_or(true) + }); + let mut music = Vec::new(); + for entry in walker { + match entry { + Err(e) => eprintln!("error when reading music dir, continuing: {:?}", e), + Ok(entry) => { + if entry.file_type().is_file() && entry.path().extension() != Some(std::ffi::OsStr::new("jpg")){ + music.push(entry.path().to_owned()); + } + } + } + } + println!("music dir skimmed"); + use rand::seq::SliceRandom; + use rand::SeedableRng; + let mut rng = rand::rngs::SmallRng::seed_from_u64(0); + music.shuffle(&mut rng); + println!("loaded {} \"songs\"", music.len()); + + /* + for i in (0..music.len()).rev() { + enum Err{ + Empty, + File, + } + let c = || -> Result<(), Err> { + // we might run out of music cause we are deliting inline, this is fine. + let choice = &music.get(i).ok_or(Err::Empty)?; + + let f = std::fs::File::open(&choice).map_err(|_| Err::File)?; + let rdr = BufReader::new(f); + let _d = rodio::Decoder::new(rdr).map_err(|_| Err::File)?; + Ok(()) + }; + match (c)() { + Err(Err::File) => {dbg!(music.remove(i));}, + _ => (), + } + } + */ + println!("checked all songs"); + println!("opening audio output"); + let (_stream, stream_handle) = rodio::OutputStream::try_default() + .expect("could not open audio output, or could not find any"); + let mut sink = rodio::Sink::try_new(&stream_handle).expect("could not create sink"); + println!("audio output opened"); + + use std::io::BufRead; + use std::io::BufReader; + let mut port = BufReader::new(port); + + // wage has valid range 0-5000 + let mut max: usize = 5000; + let mut preval = 0; + let mut prechoice = 0; + let mut readbuf = String::new(); + let mut n_changed = 0; + + use std::io::Write; + port.get_mut().write(b"r").unwrap(); + + loop { + readbuf.clear(); + port.read_line(&mut readbuf).unwrap(); + //println!("got line: {}", readbuf); + let err = "got invalid message from wage"; + let w: usize = readbuf.trim().parse().expect(err); + if w == 8888 || w == 69_69_69_69 { + // special values: 8888 and 69696969 + // are turned off and EEEE + } else { + max = max.max(w); + let choice = (w * (music.len() - 1)) / max; + let absdiff = w.max(preval) - w.min(preval); + if absdiff > 1 && choice != prechoice { + n_changed += 1; + } else { + n_changed = 0; + } + if n_changed >= 7 { + let choicef = &music[(music.len() - 1) - choice]; + println!("changing song to {:?}", choicef); + let mut c = || -> Result<(), ()> { + let f = std::fs::File::open(choicef).map_err(|_| ())?; + let rdr = BufReader::new(f); + let d = rodio::Decoder::new(rdr).map_err(|_| ())?; + //let s = rodio::source::SineWave::new(440); + let newsink = + rodio::Sink::try_new(&stream_handle).expect("could not create sink"); + newsink.append(d); + + sink.stop(); + sink = newsink; + Ok(()) + }; + if let Err(_error) = (c)() { + println!("music was not music"); + let r = music.remove((music.len() - 1) - choice); + println!("removed {:?}", r); + } else { + preval = w; + prechoice = choice; + n_changed = 0; + } + } + } + + std::thread::sleep(std::time::Duration::from_millis(100)); + port.get_mut().write(b"r").unwrap(); + } +}