use std::path::Path;
use dspk_core::{DspResult, RationalTime, RecordingSource, SampleRate, SignalUnit};
use super::acquisition::{is_nwb_zarr, list_series, NwbZarrRecording, SeriesEntry};
use dspk_io::core::sources::{SourceEntry, SourceKind};
use dspk_io::core::Format;
pub struct Nwb;
fn read_unit(series: &SeriesEntry) -> SignalUnit {
if series.neurodata_type == "ElectricalSeries" || series.unit == "volts" {
return SignalUnit::Microvolt;
}
match series.unit.as_str() {
"a.u." | "" => SignalUnit::Dimensionless,
other => SignalUnit::Other(other.to_string()),
}
}
impl Format for Nwb {
fn name(&self) -> &'static str {
"nwb"
}
fn detect(&self, path: &Path) -> bool {
is_nwb_zarr(path)
}
fn sources(&self, path: &Path) -> DspResult<Vec<SourceEntry>> {
list_series(path)
.into_iter()
.map(|s| {
let unit = read_unit(&s);
Ok(SourceEntry {
name: s.path.rsplit('/').next().unwrap_or(&s.path).to_string(),
kind: if s.neurodata_type == "ElectricalSeries" { SourceKind::Electrical } else { SourceKind::from_unit(&unit) },
channels: s.channels,
samples: s.samples,
sample_rate: SampleRate::new(s.rate)?,
start_time: RationalTime::from_seconds_f64(s.start_time)?,
format: s.format,
unit,
id: s.path,
})
})
.collect()
}
fn open(&self, path: &Path, id: &str) -> DspResult<Box<dyn RecordingSource>> {
Ok(Box::new(NwbZarrRecording::open_series(path, id)?))
}
fn open_default(&self, path: &Path) -> DspResult<Box<dyn RecordingSource>> {
Ok(Box::new(NwbZarrRecording::open(path)?))
}
}