made more functional'n shit
This commit is contained in:
parent
5ffe22ce17
commit
3d7f17723c
1 changed files with 161 additions and 76 deletions
237
src/main.rs
237
src/main.rs
|
@ -1,4 +1,7 @@
|
|||
use serial::SerialPort;
|
||||
use std::io::BufRead;
|
||||
use std::io::BufReader;
|
||||
use std::io::Result as IoResult;
|
||||
|
||||
use walkdir::WalkDir;
|
||||
fn main() {
|
||||
|
@ -39,8 +42,10 @@ fn main() {
|
|||
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());
|
||||
if entry.file_type().is_file()
|
||||
&& 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);
|
||||
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()
|
||||
|
@ -80,67 +64,168 @@ fn main() {
|
|||
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);
|
||||
#[derive(Clone, Copy)]
|
||||
struct Hyst {
|
||||
max: usize,
|
||||
prechoice: usize,
|
||||
/// value when the choice was last changed
|
||||
prechoice_val: usize,
|
||||
/// value of last read
|
||||
preval: usize,
|
||||
/// number of times the same (but changed) value has been read
|
||||
stability: usize,
|
||||
}
|
||||
|
||||
// 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;
|
||||
let equality_range = 1;
|
||||
let stability_tresh = 7;
|
||||
|
||||
use std::io::Write;
|
||||
port.get_mut().write(b"r").unwrap();
|
||||
let hyst = Hyst {
|
||||
// wage has valid range 0-5000
|
||||
max: 5000,
|
||||
prechoice: 0,
|
||||
prechoice_val: 0,
|
||||
preval: 0,
|
||||
stability: 0,
|
||||
};
|
||||
|
||||
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);
|
||||
let musiclen = music.len();
|
||||
|
||||
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);
|
||||
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 {
|
||||
preval = w;
|
||||
prechoice = choice;
|
||||
n_changed = 0;
|
||||
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 rdr = BufReader::new(f);
|
||||
rodio::Decoder::new(rdr).map_err(|_| ())
|
||||
};
|
||||
match (c)() {
|
||||
Ok(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);
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
port.get_mut().write(b"r").unwrap();
|
||||
sink.stop();
|
||||
sink = newsink;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum PortIterErr {
|
||||
Io(std::io::Error),
|
||||
Parse(std::num::ParseIntError),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for PortIterErr {
|
||||
fn from(e: std::io::Error) -> Self {
|
||||
Self::Io(e)
|
||||
}
|
||||
}
|
||||
impl From<std::num::ParseIntError> for PortIterErr {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue