use edfplus::{EdfWriter, EdfReader, SignalParam};
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let file_path = "test_annotation_reading.edf";
let _ = fs::remove_file(file_path);
println!("Creating EDF+ file with annotations...");
let annotation_count = {
let mut writer = EdfWriter::create(file_path)?;
writer.set_patient_info("TEST001", "M", "01-JAN-2000", "Test Patient")?;
let signal_param = SignalParam {
label: "EEG1".to_string(),
samples_in_file: 0, physical_max: 100.0,
physical_min: -100.0,
digital_max: 32767,
digital_min: -32768,
samples_per_record: 100,
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:70Hz".to_string(),
transducer: "AgAgCl electrode".to_string(),
};
writer.add_signal(signal_param)?;
writer.set_datarecord_duration(1.0)?;
writer.add_annotation(1.5, Some(0.5), "Test annotation 1")?;
writer.add_annotation(3.0, None, "Test annotation 2")?;
writer.add_annotation(5.25, Some(1.0), "Test annotation 3 with longer duration")?;
writer.add_annotation(7.8, None, "Final test annotation")?;
for record in 0..10 {
let mut samples = Vec::new();
for i in 0..100 {
let t = (record * 100 + i) as f64 * 0.01; let value = 50.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin(); samples.push(value);
}
writer.write_samples(&[samples])?;
}
let count = writer.annotation_count();
writer.finalize()?;
count
};
println!("Written {} annotations to file", annotation_count);
println!("\nReading EDF+ file and parsing annotations...");
let reader = EdfReader::open(file_path)?;
println!("File info:");
println!(" Signals: {}", reader.header().signals.len());
println!(" Data records: {}", reader.header().datarecords_in_file);
println!(" Duration per record: {:.3}s", reader.header().datarecord_duration as f64 / 10000000.0);
let annotations = reader.annotations();
println!("\nFound {} annotations:", annotations.len());
for (i, annotation) in annotations.iter().enumerate() {
let onset_seconds = annotation.onset as f64 / 10000000.0;
let duration_seconds = if annotation.duration >= 0 {
annotation.duration as f64 / 10000000.0
} else {
-1.0
};
println!(" {}: onset={:.3}s, duration={:.3}s, text='{}'",
i + 1,
onset_seconds,
duration_seconds,
annotation.description);
}
let expected_annotations = vec![
(1.5, Some(0.5), "Test annotation 1"),
(3.0, None, "Test annotation 2"),
(5.25, Some(1.0), "Test annotation 3 with longer duration"),
(7.8, None, "Final test annotation"),
];
println!("\nValidation:");
let mut all_correct = true;
if annotations.len() != expected_annotations.len() {
println!(" ERROR: Expected {} annotations, found {}", expected_annotations.len(), annotations.len());
all_correct = false;
} else {
for (i, (expected_onset, expected_duration, expected_text)) in expected_annotations.iter().enumerate() {
let annotation = &annotations[i];
let onset_seconds = annotation.onset as f64 / 10000000.0;
let duration_seconds = if annotation.duration >= 0 {
Some(annotation.duration as f64 / 10000000.0)
} else {
None
};
let onset_ok = (onset_seconds - expected_onset).abs() < 0.001;
let duration_ok = match (duration_seconds, expected_duration) {
(Some(actual), Some(expected)) => (actual - expected).abs() < 0.001,
(None, None) => true,
_ => false,
};
let text_ok = annotation.description == *expected_text;
if onset_ok && duration_ok && text_ok {
println!(" ✓ Annotation {} correct", i + 1);
} else {
println!(" ✗ Annotation {} incorrect:", i + 1);
if !onset_ok {
println!(" - Onset: expected {:.3}s, got {:.3}s", expected_onset, onset_seconds);
}
if !duration_ok {
println!(" - Duration: expected {:?}s, got {:?}s", expected_duration, duration_seconds);
}
if !text_ok {
println!(" - Text: expected '{}', got '{}'", expected_text, annotation.description);
}
all_correct = false;
}
}
}
if all_correct {
println!("\n✓ All annotations parsed correctly!");
} else {
println!("\n✗ Some annotations were not parsed correctly.");
}
let _ = fs::remove_file(file_path);
Ok(())
}