-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
237 additions
and
97 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
#[cfg(test)] | ||
mod eeg_test { | ||
use num_rational::Rational64; | ||
|
||
use crate::{ | ||
datagen::mod_1d::{ | ||
csv_to_normalform, eeg_data_to_normal_form, eeg_datum_to_point_op, CsvData, | ||
}, | ||
NameSet, NormalForm, PointOp, | ||
}; | ||
#[test] | ||
fn test_eeg_datum_to_point_op() { | ||
let mut names = NameSet::new(); | ||
names.insert("data.csv".to_string()); | ||
let result = eeg_datum_to_point_op(1.0e-14, None, 2.0e14, "data.csv"); | ||
let expected = PointOp { | ||
fa: Rational64::new(2, 1), | ||
l: Rational64::new(1, 50), | ||
names, | ||
..PointOp::default() | ||
}; | ||
assert_eq!(result, expected); | ||
} | ||
|
||
#[test] | ||
fn test_eeg_datum_to_normal_form() { | ||
let eeg_data = CsvData { | ||
data: vec![0.5e-14, 1.0e-14, 1.5e-14], | ||
}; | ||
let mut names = NameSet::new(); | ||
names.insert("data.csv".to_string()); | ||
let result = eeg_data_to_normal_form(&eeg_data, 2.0e14, "data.csv"); | ||
let expected = NormalForm { | ||
operations: vec![vec![ | ||
PointOp { | ||
fa: Rational64::new(1, 1), | ||
l: Rational64::new(1, 50), | ||
names: names.clone(), | ||
..PointOp::default() | ||
}, | ||
PointOp { | ||
fa: Rational64::new(3, 2), | ||
l: Rational64::new(1, 50), | ||
names: names.clone(), | ||
..PointOp::default() | ||
}, | ||
PointOp { | ||
fa: Rational64::new(2, 1), | ||
l: Rational64::new(1, 50), | ||
names, | ||
..PointOp::default() | ||
}, | ||
]], | ||
length_ratio: Rational64::new(3, 50), | ||
}; | ||
assert_eq!(result, expected); | ||
} | ||
#[test] | ||
fn test_csv_to_normalform() { | ||
let result = csv_to_normalform( | ||
"./src/datagen/test_data.csv", | ||
Some(Rational64::new(200_000_000_000_000, 1)), | ||
) | ||
.unwrap(); | ||
|
||
let mut names = NameSet::new(); | ||
names.insert("test_data.csv".to_string()); | ||
let expected = NormalForm { | ||
operations: vec![vec![ | ||
PointOp { | ||
fa: Rational64::new(1, 1), | ||
l: Rational64::new(1, 50), | ||
names: names.clone(), | ||
..PointOp::default() | ||
}, | ||
PointOp { | ||
fa: Rational64::new(3, 2), | ||
l: Rational64::new(1, 50), | ||
names: names.clone(), | ||
..PointOp::default() | ||
}, | ||
PointOp { | ||
fa: Rational64::new(2, 1), | ||
l: Rational64::new(1, 50), | ||
names, | ||
..PointOp::default() | ||
}, | ||
]], | ||
length_ratio: Rational64::new(3, 50), | ||
}; | ||
assert_eq!(result, expected); | ||
} | ||
} |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
use crate::{NameSet, NormalForm, Normalize, Op, OscType, PointOp, Term, ASR}; | ||
use num_rational::{Ratio, Rational64}; | ||
use scop::Defs; | ||
use serde::{Deserialize, Serialize}; | ||
use std::str::FromStr; | ||
use std::{fs::File, path::Path}; | ||
use weresocool_error::Error; | ||
use weresocool_ring_buffer::RingBuffer; | ||
use weresocool_shared::helpers::r_to_f32; | ||
|
||
#[derive(Debug, Clone, Serialize, Deserialize)] | ||
pub struct CsvData { | ||
pub data: Vec<f32>, | ||
} | ||
|
||
pub fn csv_to_normalform(filename: &str, scale: Option<Rational64>) -> Result<NormalForm, Error> { | ||
let data = get_data(filename.into())?; | ||
let path = Path::new(&filename); | ||
Ok(vec_eeg_data_to_normal_form( | ||
data, | ||
if let Some(s) = scale { | ||
r_to_f32(s) | ||
} else { | ||
1.0 | ||
}, | ||
path.file_name() | ||
.unwrap() | ||
.to_string_lossy() | ||
.to_string() | ||
.as_str(), | ||
)) | ||
} | ||
|
||
fn vec_eeg_data_to_normal_form(data: Vec<CsvData>, scale: f32, filename: &str) -> NormalForm { | ||
let mut nfs: Vec<NormalForm> = data | ||
.iter() | ||
.map(|stream| eeg_data_to_normal_form(stream, scale, filename)) | ||
.collect(); | ||
|
||
let overlay = Op::Overlay { | ||
operations: nfs.iter_mut().map(|nf| Term::Nf(nf.to_owned())).collect(), | ||
}; | ||
|
||
let mut nf = NormalForm::init(); | ||
overlay | ||
.apply_to_normal_form(&mut nf, &mut Defs::new()) | ||
.expect("unable to normalize"); | ||
nf | ||
} | ||
|
||
pub fn eeg_data_to_normal_form(data: &CsvData, scale: f32, filename: &str) -> NormalForm { | ||
let mut length_ratio = Rational64::new(0, 1); | ||
|
||
let mut buffer = RingBuffer::<f32>::new(50); | ||
|
||
let point_ops: Vec<PointOp> = data | ||
.data | ||
.iter() | ||
.map(|value| { | ||
let op = eeg_datum_to_point_op(*value, Some(&mut buffer), scale, filename); | ||
length_ratio += op.l; | ||
op | ||
}) | ||
.collect(); | ||
|
||
NormalForm { | ||
length_ratio, | ||
operations: vec![point_ops], | ||
} | ||
} | ||
|
||
pub fn f32_to_rational(mut float: f32) -> Rational64 { | ||
if !float.is_finite() || float > 100_000_000.0 { | ||
float = 0.0 | ||
} | ||
let float_string = format!("{:.8}", float); | ||
let decimal = float_string.split('.').collect::<Vec<&str>>()[1]; | ||
let den = i64::pow(10, decimal.len() as u32); | ||
let num = i64::from_str(&float_string.replace('.', "")) | ||
.unwrap_or_else(|_| panic!("error converting {} to i64", float_string)); | ||
|
||
Ratio::new(num, den) | ||
} | ||
|
||
pub fn eeg_datum_to_point_op( | ||
datum: f32, | ||
buffer: Option<&mut RingBuffer<f32>>, | ||
scale: f32, | ||
filename: &str, | ||
) -> PointOp { | ||
let mut nameset = NameSet::new(); | ||
nameset.insert(filename.to_string()); | ||
let mut datum = datum.abs() * scale; | ||
if let Some(b) = buffer { | ||
b.push(datum); | ||
|
||
let b_vec = b.to_vec(); | ||
let sum: f32 = b_vec.iter().sum(); | ||
datum = sum / b_vec.len() as f32; | ||
} | ||
|
||
let fa = f32_to_rational(datum); | ||
PointOp { | ||
// fm, | ||
fm: Rational64::new(1, 1), | ||
fa, | ||
l: Rational64::new(2, 100), | ||
g: Rational64::new(1, 1), | ||
pm: Rational64::new(1, 1), | ||
pa: Rational64::new(0, 1), | ||
asr: ASR::Long, | ||
portamento: Rational64::new(1, 1), | ||
attack: Rational64::new(1, 1), | ||
decay: Rational64::new(1, 1), | ||
reverb: None, | ||
osc_type: OscType::None, | ||
names: nameset, | ||
} | ||
} | ||
|
||
fn get_data(filename: String) -> Result<Vec<CsvData>, Error> { | ||
let path = Path::new(&filename); | ||
let cwd = std::env::current_dir()?; | ||
let file = File::open(path).unwrap_or_else(|_| { | ||
panic!( | ||
"unable to read file: {}. current working directory is: {}", | ||
path.display(), | ||
cwd.display() | ||
) | ||
}); | ||
let mut rdr = csv::ReaderBuilder::new() | ||
.has_headers(false) | ||
.delimiter(b',') | ||
.from_reader(file); | ||
|
||
Ok(rdr | ||
.deserialize::<CsvData>() | ||
.map(|datum| datum.expect("Error deserializing datum")) | ||
.collect()) | ||
} |
This file was deleted.
Oops, something went wrong.