//! # rtx-neuro-io //! //! File format readers and writers for neuroimaging data. //! //! ## Supported Formats //! //! ### EEG Formats //! - **EDF/EDF+** - European Data Format (most common research format) //! - **BDF** - BioSemi 24-bit variant //! - **BrainVision** - .vhdr/.vmrk/.eeg files //! - **EGI** - Electrical Geodesics (.raw, .mff) //! //! ### MEG Formats //! - **FIF** - Elekta/Neuromag format //! - **CTF** - CTF MEG Systems (.ds directories) //! - **BTi/4D** - 4D-Neuroimaging/BTi systems //! - **KIT** - Yokogawa/KIT/Ricoh systems (.con, .sqd) //! //! ### Dataset Formats //! - **BIDS** - Brain Imaging Data Structure (directory-based) //! //! ## Usage //! //! ```rust,ignore //! use rtx_neuro_io::edf::EdfReader; //! use rtx_neuro_io::fif::FifReader; //! use rtx_neuro_io::ctf::CtfReader; //! use rtx_neuro_io::bti::BtiReader; //! use rtx_neuro_io::kit::KitReader; //! use rtx_neuro_io::egi::EgiReader; //! //! // Read EDF file //! let reader = EdfReader::open("recording.edf")?; //! let data = reader.read_data(0.0, 10.0)?; // Read 10 seconds //! //! // Read FIF file (Elekta/Neuromag MEG) //! let reader = FifReader::open("sample_raw.fif")?; //! let data = reader.read_data(0.0, 10.0)?; //! //! // Read CTF dataset (directory-based) //! let reader = CtfReader::open("experiment.ds")?; //! let data = reader.read_data(0.0, 10.0)?; //! //! // Read 4D-Neuroimaging/BTi data //! let reader = BtiReader::open("subject_data")?; //! let data = reader.read_data(0.0, 10.0)?; //! //! // Read Yokogawa/KIT data //! let reader = KitReader::open("recording.con")?; //! let data = reader.read_data(0.0, 10.0)?; //! //! // Read EGI data //! let reader = EgiReader::open("recording.raw")?; //! let data = reader.read_data(0.0, 10.0)?; //! //! // Open BIDS dataset //! use rtx_neuro_io::bids::BidsDataset; //! let dataset = BidsDataset::open("my_bids_dataset")?; //! println!("Dataset: {}", dataset.name()); //! for subject in dataset.subject_labels() { //! println!(" Subject: {}", subject); //! } //! ``` #![warn(missing_docs)] pub mod bids; pub mod brainvision; pub mod bti; pub mod ctf; pub mod edf; pub mod egi; pub mod fif; pub mod kit; // Re-export main types pub use bids::{ BidsDataset, BidsFile, BidsSession, BidsSubject, DatasetDescription, FileEntities, is_bids_dataset, parse_bids_filename, }; pub use brainvision::BrainVisionReader; pub use bti::{BtiChannel, BtiChannelKind, BtiConfig, BtiReader}; pub use ctf::{CtfChannel, CtfChannelKind, CtfReader, Res4Header}; pub use edf::{EdfHeader, EdfReader}; pub use egi::{EgiChannel, EgiChannelKind, EgiFormat, EgiHeader, EgiReader}; pub use fif::{FifChannel, FifInfo, FifReader}; pub use kit::{KitChannel, KitChannelKind, KitHeader, KitReader}; use std::path::Path; /// Error types for I/O operations #[derive(Debug, thiserror::Error)] pub enum IoError { /// File I/O error #[error("File I/O error: {0}")] Io(#[from] std::io::Error), /// Invalid file format #[error("Invalid file format: {0}")] InvalidFormat(String), /// Unsupported format version #[error("Unsupported format version: {0}")] UnsupportedVersion(String), /// Header parsing error #[error("Header parsing error: {0}")] HeaderParse(String), /// Data parsing error #[error("Data parsing error: {0}")] DataParse(String), /// File not found #[error("File not found: {0}")] FileNotFound(String), /// Channel not found #[error("Channel not found: {0}")] ChannelNotFound(String), } /// Result type for I/O operations pub type IoResult = Result; /// Trait for file format readers pub trait NeuroReader { /// Read file header/metadata fn read_header(&mut self) -> IoResult<()>; /// Get sampling frequency in Hz fn sfreq(&self) -> f64; /// Get number of channels fn n_channels(&self) -> usize; /// Get total number of samples per channel fn n_samples(&self) -> usize; /// Get channel names fn channel_names(&self) -> Vec; /// Read raw data for specified time range /// Returns data as [n_channels x n_samples] fn read_raw_data(&mut self, tmin: f64, tmax: f64) -> IoResult>; /// Read all data fn read_all_data(&mut self) -> IoResult> { let duration = self.n_samples() as f64 / self.sfreq(); self.read_raw_data(0.0, duration) } } /// Detect file format from path pub fn detect_format(path: impl AsRef) -> Option { let path = path.as_ref(); // Check for directory-based formats if path.is_dir() { if let Some(name) = path.file_name().and_then(|n| n.to_str()) { if name.ends_with(".ds") { return Some(FileFormat::Ctf); } if name.ends_with(".mff") { return Some(FileFormat::Egi); } // Check for BTi directory (contains config file) let config_path = path.join("config"); if config_path.exists() { return Some(FileFormat::Bti); } } } // Check file extension let ext = path.extension()?.to_str()?.to_lowercase(); match ext.as_str() { "edf" => Some(FileFormat::Edf), "bdf" => Some(FileFormat::Bdf), "vhdr" => Some(FileFormat::BrainVision), "set" => Some(FileFormat::EegLab), "fif" => Some(FileFormat::Fif), "ds" => Some(FileFormat::Ctf), "cnt" => Some(FileFormat::Neuroscan), "nwb" => Some(FileFormat::Nwb), "con" | "sqd" => Some(FileFormat::Kit), "raw" => Some(FileFormat::Egi), "mff" => Some(FileFormat::Egi), _ => None, } } /// Supported file formats #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum FileFormat { /// EDF (European Data Format) Edf, /// BDF (BioSemi 24-bit) Bdf, /// BrainVision (.vhdr/.vmrk/.eeg) BrainVision, /// EEGLAB (.set) EegLab, /// Elekta/Neuromag FIF Fif, /// CTF MEG Ctf, /// 4D-Neuroimaging/BTi MEG Bti, /// Yokogawa/KIT/Ricoh MEG Kit, /// EGI (.raw, .mff) Egi, /// Neuroscan (.cnt) Neuroscan, /// Neurodata Without Borders Nwb, }