made more functional'n shit
This commit is contained in:
parent
5ffe22ce17
commit
3d7f17723c
1 changed files with 161 additions and 76 deletions
243
src/main.rs
243
src/main.rs
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue