made more functional'n shit

This commit is contained in:
_ 2020-10-20 14:10:54 +02:00
parent 5ffe22ce17
commit 3d7f17723c

View file

@ -1,4 +1,7 @@
use serial::SerialPort; use serial::SerialPort;
use std::io::BufRead;
use std::io::BufReader;
use std::io::Result as IoResult;
use walkdir::WalkDir; use walkdir::WalkDir;
fn main() { fn main() {
@ -39,8 +42,10 @@ fn main() {
match entry { match entry {
Err(e) => eprintln!("error when reading music dir, continuing: {:?}", e), Err(e) => eprintln!("error when reading music dir, continuing: {:?}", e),
Ok(entry) => { Ok(entry) => {
if entry.file_type().is_file() && entry.path().extension() != Some(std::ffi::OsStr::new("jpg")){ if entry.file_type().is_file()
music.push(entry.path().to_owned()); && entry.path().extension() != Some(std::ffi::OsStr::new("jpg"))
{
music.push(Some(entry.path().to_owned()));
} }
} }
} }
@ -52,27 +57,6 @@ fn main() {
music.shuffle(&mut rng); music.shuffle(&mut rng);
println!("loaded {} \"songs\"", music.len()); 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!("checked all songs");
println!("opening audio output"); println!("opening audio output");
let (_stream, stream_handle) = rodio::OutputStream::try_default() let (_stream, stream_handle) = rodio::OutputStream::try_default()
@ -80,67 +64,168 @@ fn main() {
let mut sink = rodio::Sink::try_new(&stream_handle).expect("could not create sink"); let mut sink = rodio::Sink::try_new(&stream_handle).expect("could not create sink");
println!("audio output opened"); println!("audio output opened");
use std::io::BufRead; #[derive(Clone, Copy)]
use std::io::BufReader; struct Hyst {
let mut port = BufReader::new(port); max: usize,
prechoice: usize,
// wage has valid range 0-5000 /// value when the choice was last changed
let mut max: usize = 5000; prechoice_val: usize,
let mut preval = 0; /// value of last read
let mut prechoice = 0; preval: usize,
let mut readbuf = String::new(); /// number of times the same (but changed) value has been read
let mut n_changed = 0; stability: usize,
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]; let equality_range = 1;
println!("changing song to {:?}", choicef); let stability_tresh = 7;
let mut c = || -> Result<(), ()> {
let hyst = Hyst {
// wage has valid range 0-5000
max: 5000,
prechoice: 0,
prechoice_val: 0,
preval: 0,
stability: 0,
};
let musiclen = music.len();
let read_delay = std::time::Duration::from_millis(100);
// first remove noise
let iter = PortIter::new(port, read_delay)
.unwrap()
.map(|e| e.unwrap())
.scan(hyst, |hyst, el| {
hyst.max = hyst.max.max(el);
let absdiff = el.max(hyst.prechoice_val) - el.min(hyst.prechoice_val);
if absdiff > equality_range {
if hyst.preval == el {
hyst.stability += 1;
} else {
hyst.stability = 0;
}
if hyst.stability > stability_tresh {
let choice = (el * (musiclen - 1)) / hyst.max;
if choice != hyst.prechoice {
hyst.prechoice = choice;
hyst.stability = 0;
hyst.preval = el;
return Some(Some((el, hyst.max)));
}
}
}
Some(None)
});
// next: turn de-noised into a decoder
let iter = iter
// skip thing the denoiser denoised
.flatten()
.map(|(e, max)| {
let decoder;
// re-run until we hit actually valid music files
loop {
let base = (e * (music.len() - 1)) / max;
let mut delta: isize = 0;
let choicef;
let choice;
// search for non-deleted paths in a cyclic pattern around base choice
// (0, -1, 1, -2, 2...)
loop {
let modchoice = if delta > 0 {
let c = base + (delta as usize);
delta = -delta;
c
} else {
let c = base - (delta as usize);
delta = (-delta) + 1;
c
};
if let Some(Some(c)) = music.get(modchoice) {
choicef = c;
choice = modchoice;
break;
}
}
// try to decode
let c = || -> Result<rodio::Decoder<_>, ()> {
let f = std::fs::File::open(choicef).map_err(|_| ())?; let f = std::fs::File::open(choicef).map_err(|_| ())?;
let rdr = BufReader::new(f); let rdr = BufReader::new(f);
let d = rodio::Decoder::new(rdr).map_err(|_| ())?; rodio::Decoder::new(rdr).map_err(|_| ())
//let s = rodio::source::SineWave::new(440); };
let newsink = match (c)() {
rodio::Sink::try_new(&stream_handle).expect("could not create sink"); Ok(d) => {
newsink.append(d); decoder = d;
break;
}
Err(()) => {
eprintln!("{:?} was not actually music", choicef);
music[choice] = None;
}
}
}
decoder
});
// now just play the decoder
for decoder in iter {
let newsink = rodio::Sink::try_new(&stream_handle).expect("could not create sink");
newsink.append(decoder);
sink.stop(); sink.stop();
sink = newsink; sink = newsink;
Ok(()) }
}; }
if let Err(_error) = (c)() {
println!("music was not music"); #[derive(Debug)]
let r = music.remove((music.len() - 1) - choice); enum PortIterErr {
println!("removed {:?}", r); Io(std::io::Error),
} else { Parse(std::num::ParseIntError),
preval = w; }
prechoice = choice;
n_changed = 0; impl From<std::io::Error> for PortIterErr {
} fn from(e: std::io::Error) -> Self {
} Self::Io(e)
} }
}
std::thread::sleep(std::time::Duration::from_millis(100)); impl From<std::num::ParseIntError> for PortIterErr {
port.get_mut().write(b"r").unwrap(); fn from(e: std::num::ParseIntError) -> Self {
Self::Parse(e)
}
}
struct PortIter<S: SerialPort> {
port: BufReader<S>,
delay: std::time::Duration,
}
impl<S: SerialPort> PortIter<S> {
fn new(mut p: S, delay: std::time::Duration) -> IoResult<Self> {
p.write_all(b"r")?;
Ok(Self {
port: BufReader::new(p),
delay,
})
}
}
impl<S: SerialPort> Iterator for PortIter<S> {
type Item = Result<usize, PortIterErr>;
fn next(&mut self) -> Option<Result<usize, PortIterErr>> {
let mut buf = String::new();
let r = self.port.read_line(&mut buf);
match r {
Ok(0) => return None,
Err(e) => return Some(Result::Err(e.into())),
Ok(_) => (),
};
let num = match buf.parse::<usize>() {
Err(e) => return Some(Result::Err(e.into())),
Ok(num) => num,
};
match self.port.get_mut().write_all(b"r") {
Ok(_) => (),
Err(e) => return Some(Result::Err(e.into())),
}
std::thread::sleep(self.delay);
Some(Result::Ok(num))
} }
} }