use std::error::Error;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use crate::Curve;
use ndarray::Array1;
pub fn load_frequency_response(
path: &PathBuf,
) -> Result<(Array1<f64>, Array1<f64>), Box<dyn std::error::Error>> {
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut frequencies = Vec::new();
let mut spl_values = Vec::new();
let mut detected_columns = 0;
for (line_num, line) in reader.lines().enumerate() {
let line = line?;
let line = line.trim();
if line.is_empty() || line.starts_with('#') || line.starts_with("//") {
continue;
}
if line_num == 0 && (line.contains("freq") || line.contains("Freq") || line.contains("Hz"))
{
continue;
}
let parts: Vec<&str> = if line.contains(',') {
line.split(',').map(|s| s.trim()).collect()
} else {
line.split_whitespace().collect()
};
if detected_columns == 0 && parts.len() >= 2 {
detected_columns = parts.len();
}
if detected_columns == 2 && parts.len() >= 2 {
if let (Ok(freq), Ok(spl)) = (parts[0].parse::<f64>(), parts[1].parse::<f64>()) {
frequencies.push(freq);
spl_values.push(spl);
}
} else if detected_columns == 4 && parts.len() >= 4 {
if let (Ok(freq_l), Ok(spl_l), Ok(_freq_r), Ok(spl_r)) = (
parts[0].parse::<f64>(),
parts[1].parse::<f64>(),
parts[2].parse::<f64>(),
parts[3].parse::<f64>(),
) {
frequencies.push(freq_l);
spl_values.push((spl_l + spl_r) / 2.0); }
}
}
if frequencies.is_empty() {
return Err("No valid frequency response data found in file".into());
}
Ok((Array1::from_vec(frequencies), Array1::from_vec(spl_values)))
}
pub fn read_curve_from_csv(path: &PathBuf) -> Result<Curve, Box<dyn Error>> {
match load_driver_measurement(path) {
Ok((freq, spl, phase)) => Ok(crate::Curve { freq, spl, phase }),
Err(_) => {
let result = load_frequency_response(path)?;
Ok(crate::Curve {
freq: Array1::from(result.0),
spl: Array1::from(result.1),
phase: None,
})
}
}
}
#[allow(clippy::type_complexity)]
pub fn load_driver_measurement(
path: &PathBuf,
) -> Result<(Array1<f64>, Array1<f64>, Option<Array1<f64>>), Box<dyn std::error::Error>> {
let file = File::open(path)?;
let reader = BufReader::new(file);
let mut frequencies = Vec::new();
let mut spl_values = Vec::new();
let mut phase_values = Vec::new();
let mut freq_col: Option<usize> = None;
let mut spl_col: Option<usize> = None;
let mut phase_col: Option<usize> = None;
let mut header_parsed = false;
for (line_num, line) in reader.lines().enumerate() {
let line = line?;
let line = line.trim();
if line.is_empty() || line.starts_with('#') || line.starts_with("//") {
continue;
}
let parts: Vec<&str> = if line.contains(',') {
line.split(',').map(|s| s.trim()).collect()
} else {
line.split_whitespace().collect()
};
if line_num == 0 && !header_parsed {
let is_header = parts.iter().any(|p| {
let lower = p.to_lowercase();
lower.contains("freq")
|| lower.contains("hz")
|| lower.contains("spl")
|| lower.contains("phase")
|| lower.contains("db")
});
if is_header {
for (idx, col_name) in parts.iter().enumerate() {
let lower = col_name.to_lowercase();
if freq_col.is_none()
&& (lower.contains("freq") || lower == "hz" || lower == "frequency_hz")
{
freq_col = Some(idx);
} else if spl_col.is_none()
&& (lower.contains("spl")
|| lower.contains("magnitude")
|| lower == "db"
|| lower == "spl_db")
{
spl_col = Some(idx);
} else if phase_col.is_none()
&& (lower.contains("phase") || lower == "phase_deg")
{
phase_col = Some(idx);
}
}
header_parsed = true;
continue; }
if parts.len() >= 2 {
freq_col = Some(0);
spl_col = Some(1);
if parts.len() >= 3 {
phase_col = Some(2);
}
}
header_parsed = true;
}
let freq_idx = freq_col.unwrap_or(0);
let spl_idx = spl_col.unwrap_or(1);
if parts.len() > freq_idx
&& parts.len() > spl_idx
&& let (Ok(freq), Ok(spl)) = (
parts[freq_idx].parse::<f64>(),
parts[spl_idx].parse::<f64>(),
)
{
frequencies.push(freq);
spl_values.push(spl);
if let Some(phase_idx) = phase_col
&& parts.len() > phase_idx
&& let Ok(phase) = parts[phase_idx].parse::<f64>()
{
phase_values.push(phase);
}
}
}
if frequencies.is_empty() {
return Err("No valid driver measurement data found in file".into());
}
let phase = if !phase_values.is_empty() && phase_values.len() == frequencies.len() {
Some(Array1::from_vec(phase_values))
} else {
None
};
Ok((
Array1::from_vec(frequencies),
Array1::from_vec(spl_values),
phase,
))
}