Quick Start
Reading a file
#![allow(unused)] fn main() { use biodream::read_file; let result = read_file("recording.acq")?; // Non-fatal parse warnings (unknown section types, unexpected padding, etc.) for w in &result.warnings { eprintln!("warning: {w}"); } let df = result.into_value(); println!("{}", df.summary()); for channel in &df.channels { let samples = channel.scaled_samples(); println!( "{}: {} samples @ {} Hz", channel.name, samples.len(), channel.samples_per_second, ); } }
Reading from a stream
Any Read + Seek source works:
#![allow(unused)] fn main() { use std::io::Cursor; use biodream::read_stream; let bytes: Vec<u8> = std::fs::read("recording.acq")?; let result = read_stream(Cursor::new(&bytes))?; let df = result.into_value(); }
Lazy / streaming reader
For large files, load only channel headers up front and stream samples on demand:
#![allow(unused)] fn main() { use biodream::{LazyDatafile, ReadOptions}; let opts = ReadOptions::default(); let lazy = LazyDatafile::open("recording.acq", &opts)?; println!("channels: {}", lazy.channel_count()); // Load one channel at a time — never buffers the entire file for i in 0..lazy.channel_count() { let ch = lazy.load_channel(i)?; println!("{}: {} samples", ch.name, ch.scaled_samples().len()); } }
Accessing markers
#![allow(unused)] fn main() { let df = biodream::read_file("recording.acq")?.into_value(); for marker in &df.markers { println!( "[{:.3}s] {} — {}", marker.time_ms / 1000.0, marker.style.label, marker.text.as_deref().unwrap_or(""), ); } }
Error handling
All errors are typed BiopacError variants carrying the byte offset where the
problem was detected:
#![allow(unused)] fn main() { use biodream::BiopacError; match biodream::read_file("corrupt.acq") { Ok(r) => { /* ... */ } Err(BiopacError::UnexpectedEof { offset, expected }) => { eprintln!("truncated at byte {offset}: expected {expected} more bytes"); } Err(e) => eprintln!("parse error: {e}"), } }