public MainWindow() { bool r; do //first get HDR file and open BDF file { OpenFileDialog dlg = new OpenFileDialog(); dlg.Title = "Open Header of dataset to be edited..."; dlg.DefaultExt = ".hdr"; // Default file extension dlg.Filter = "HDR Files (.hdr)|*.hdr"; // Filter files by extension Nullable<bool> result = dlg.ShowDialog(); if (result == null || result == false) Environment.Exit(0); directory = System.IO.Path.GetDirectoryName(dlg.FileName); //will use to find other files in dataset headerFileName = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName); header = (new HeaderFileReader(dlg.OpenFile())).read(); updateFlag = header.Events.ContainsKey("**ArtifactBegin"); //indicates that we are editing a dataset that has already been edited for artifacts bdf = new BDFEDFFileReader(new FileStream(System.IO.Path.Combine(directory, header.BDFFile), FileMode.Open, FileAccess.Read)); //make list of candidate EEG channels, so that channel selection window can use it BDFLength = (double)bdf.NumberOfRecords * bdf.RecordDuration; string trans = bdf.transducer(0); //here we assumne that channel 0 is an EEG channel for (int i = 0; i < bdf.NumberOfChannels - 1; i++) //exclude Status channel if (bdf.transducer(i) == trans) EEGChannels.Add(i); Window1 w = new Window1(this); //open channel selection and file approval window r = (bool)w.ShowDialog(); } while (r == false); InitializeComponent(); Log.writeToLog("Starting EEGArtifactEditor " + Assembly.GetExecutingAssembly().GetName().Version.ToString() + " on dataset " + headerFileName); ViewerGrid.Width = BDFLength; try { //process Events in current dataset; we have to do this now in case this is an update situation, but don't have to when we finish Event.EventFactory.Instance(header.Events); // set up the factory, based on this Event dictionary //and read them in EventFileReader efr = new EventFileReader( new FileStream(System.IO.Path.Combine(directory, header.EventFile), FileMode.Open, FileAccess.Read)); // open Event file foreach (InputEvent ie in efr)// read in all Events into list events.Add(new OutputEvent(ie)); efr.Close(); //now events is list of Events in the dataset //now set zeroTime for this BDF file, after finding an appropriate (non-"naked") Event bool ok = false; foreach (OutputEvent ev in events) if (header.Events[ev.Name].IsCovered) { bdf.setZeroTime(ev); ok = true; break; } if (!ok) { ErrorWindow ew = new ErrorWindow(); ew.Message = "Unable to find a covered Event in this dataset on which to synchronize clocks. Exiting."; ew.ShowDialog(); Log.writeToLog("Unable to synchronize clocks."); this.Close(); } if (updateFlag) //re-editing this dataset for artifacts { Event.EventFactory.Instance(header.Events); // set up the factory, based on this Event dictionary //and read them in OutputEvent ev; int i = 0; double left; while (i < events.Count) { ev = events[i]; if (ev.Name == "**ArtifactBegin") { left = bdf.timeFromBeginningOfFileTo(ev); events.Remove(ev); while (i < events.Count) { ev = events[i]; if (ev.Name == "**ArtifactEnd") { MarkerCanvas.createMarkRegion(left, bdf.timeFromBeginningOfFileTo(ev)); events.Remove(ev); break; } if (ev.Name == "**ArtifactBegin") throw (new Exception("Unmatched artifact Event in Event file " + System.IO.Path.Combine(directory, header.EventFile))); i++; } } else i++; } } //initialize the individual channel canvases foreach (int chan in selectedEEGChannels) { ChannelCanvas cc = new ChannelCanvas(this, chan); currentChannelList.Add(cc); ViewerCanvas.Children.Add(cc); ViewerCanvas.Children.Add(cc.offScaleRegions); } Title = headerFileName; //set window title BDFFileInfo.Content = bdf.ToString(); HDRFileInfo.Content = header.ToString(); ElectrodeInputFileStream eif = new ElectrodeInputFileStream( new FileStream(System.IO.Path.Combine(directory, header.ElectrodeFile), FileMode.Open, FileAccess.Read)); //open Electrode file electrodes = eif.etrPositions; //initialize vertical gridline array; never more than 18 for (int i = 0; i < 18; i++) { Line l = new Line(); Grid.SetRow(l, 0); Grid.SetColumn(l, 0); l.Y1 = 0D; l.HorizontalAlignment = HorizontalAlignment.Left; l.VerticalAlignment = VerticalAlignment.Stretch; l.IsHitTestVisible = false; l.Stroke = Brushes.LightBlue; l.Visibility = Visibility.Hidden; Panel.SetZIndex(l, int.MaxValue); VerticalGrid.Children.Add(l); gridlines[i] = l; } //Initialize timer timer.AutoReset = true; timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); //Initialize channel information popup Color c1 = Color.FromArgb(0xFF, 0xF8, 0xF8, 0xF8); Color c2 = Color.FromArgb(0xFF, 0xC8, 0xC8, 0xC8); popupTB.Background = new LinearGradientBrush(c1, c2, 45D); popupTB.Foreground = Brushes.Black; popupTB.Padding = new Thickness(4D); Border b = new Border(); b.BorderThickness = new Thickness(1); b.CornerRadius = new CornerRadius(4); b.BorderBrush = Brushes.Tomato; b.Margin = new Thickness(0, 0, 24, 24); //allows drop shadow to show up b.Effect = new DropShadowEffect(); b.Child = popupTB; channelPopup.Placement = PlacementMode.MousePoint; channelPopup.AllowsTransparency = true; channelPopup.Child = b; //Initialize FOV slider FOV.Maximum = Math.Log10(BDFLength); FOV.Value = 1D; FOVMax.Text = BDFLength.ToString("0"); //Note file always uses the "main" orginal dataset name, which should be the BDFFile name; this keeps notes from all levels of //processing in the same place noteFilePath = System.IO.Path.Combine(directory, System.IO.Path.GetFileNameWithoutExtension(header.BDFFile) + ".notes.txt"); } catch (Exception ex) { ErrorWindow ew = new ErrorWindow(); ew.Message = "Error in EEGArtifactEditor initialization" + ex.Message; ew.ShowDialog(); this.Close(); //exit } //from here on the program is GUI-event driven }
public Header.Header read() { Header.Header header = new Header.Header(); try { xr.ReadStartElement("ExperimentDescription", nameSpace); xr.ReadStartElement("SoftwareVersion", nameSpace); header.SoftwareVersion = xr.ReadContentAsString(); xr.ReadEndElement(/* SoftwareVersion */); xr.ReadStartElement("Title", nameSpace); header.Title = xr.ReadContentAsString(); xr.ReadEndElement(/* Title */); xr.ReadStartElement("LongDescription", nameSpace); header.LongDescription = xr.ReadContentAsString(); xr.ReadEndElement(/* LongDescription */); header.Experimenter = new List<string>(); while (xr.Name == "Experimenter") { xr.ReadStartElement(/* Experimenter */); header.Experimenter.Add(xr.ReadContentAsString()); xr.ReadEndElement(/* Experimenter */); } xr.ReadStartElement("Status", nameSpace); header.Status = xr.ReadContentAsInt(); xr.ReadEndElement(/* Status */); if (xr.Name == "Other") { header.OtherExperimentInfo = new Dictionary<string, string>(); do { string name = xr["Name"]; xr.ReadStartElement(/* Other */); string value = xr.ReadContentAsString(); header.OtherExperimentInfo.Add(name, value); xr.ReadEndElement(/* Other */); } while (xr.Name == "Other"); } if (xr.Name == "GroupVar") { header.GroupVars = new GroupVarDictionary.GroupVarDictionary(); do { xr.ReadStartElement(/* GroupVar */); GroupVarDictionary.GVEntry gve = new GVEntry(); xr.ReadStartElement("Name", nameSpace); string name = xr.ReadContentAsString(); if (name.Length > 24) throw new Exception("name too long for GV " + name); xr.ReadEndElement(/* Name */); xr.ReadStartElement("Description", nameSpace); gve.Description = xr.ReadContentAsString(); xr.ReadEndElement(/* Description */); if (xr.Name == "GV") { gve.GVValueDictionary = new Dictionary<string, int>(); do { string key = xr["Desc", nameSpace]; xr.ReadStartElement(/* GV */); int val = xr.ReadContentAsInt(); if (val > 0) gve.GVValueDictionary.Add(key, val); else throw new Exception("invalid value for GV "+ name); xr.ReadEndElement(/* GV */); } while (xr.Name == "GV"); } header.GroupVars.Add(name, gve); xr.ReadEndElement(/* GroupVar */); } while (xr.Name == "GroupVar"); } if (xr.Name == "Event") { header.Events = new EventDictionary.EventDictionary(header.Status); do { EventDictionaryEntry ede = new EventDictionaryEntry(); if (xr.MoveToAttribute("Type")) { string s = xr.ReadContentAsString(); if (s == "*") ede.intrinsic = null; else ede.intrinsic = s != "extrinsic"; } //else Type is intrinsic by default if (xr.MoveToAttribute("Clock")) //is there a Clock attribute? { string s = xr.ReadContentAsString(); if (s == "Absolute") ede.BDFBased = false; else if (s == "BDF-based") { if (ede.IsCovered) throw new Exception("Incompatible Type and Clock attributes in Event"); ede.BDFBased = true; } else throw new Exception("Invalid Clock attribute in Event"); } //else clock is Absolute by default xr.ReadStartElement(/* Event */); xr.ReadStartElement("Name", nameSpace); string name = xr.ReadContentAsString(); xr.ReadEndElement(/* Event */); xr.ReadStartElement("Description", nameSpace); ede.Description = xr.ReadContentAsString(); xr.ReadEndElement(/* Description */); if (ede.IsCovered && !(bool)ede.intrinsic) { xr.ReadStartElement("Channel", nameSpace); ede.channelName = xr.ReadContentAsString(); xr.ReadEndElement(/* Channel */); xr.ReadStartElement("Edge", nameSpace); ede.rise = xr.ReadContentAsString() == "rising"; xr.ReadEndElement(/* Edge */); ede.location = (xr.Name == "Location" ? (xr.ReadElementContentAsString() == "after") : false); //leads by default ede.channelMax = xr.Name == "Max" ? xr.ReadElementContentAsDouble() : 0D; //zero by default ede.channelMin = xr.Name == "Min" ? xr.ReadElementContentAsDouble() : 0D; //zero by default if (ede.channelMax < ede.channelMin) throw new Exception("invalid max/min signal values in extrinsic Event " + name); //Note: Max and Min are optional; if neither is specified, 0.0 will always be used as threshold } if (xr.Name == "Ancillary") { xr.ReadStartElement(/* Ancillary */); ede.ancillarySize = xr.ReadContentAsInt(); xr.ReadEndElement(/* Ancillary */); } if (xr.Name == "GroupVar") { ede.GroupVars = new List<GVEntry>(); do { string gvName = xr["Name", nameSpace]; bool isEmpty = xr.IsEmptyElement; xr.ReadStartElement(/* GroupVar */); GVEntry gve; if (header.GroupVars.TryGetValue(gvName, out gve)) ede.GroupVars.Add(gve); else throw new Exception("invalid GroupVar " + gvName + " in Event " + name); if(!isEmpty) xr.ReadEndElement(/* GroupVar */); } while (xr.Name == "GroupVar"); } header.Events.Add(name, ede); xr.ReadEndElement(/* Event */); } while (xr.Name == "Event"); } xr.ReadEndElement(/* ExperimentDescription */); xr.ReadStartElement("SessionDescription", nameSpace); xr.ReadStartElement("Date", nameSpace); header.Date = xr.ReadContentAsString(); xr.ReadEndElement(/* Date */); xr.ReadStartElement("Time", nameSpace); header.Time = xr.ReadContentAsString(); xr.ReadEndElement(/* Time */); xr.ReadStartElement("Subject", nameSpace); header.Subject = xr.ReadContentAsInt(); xr.ReadEndElement(/* Subject */); if (xr.Name == "Agent") { xr.ReadStartElement(/* Agent */); header.Agent = xr.ReadContentAsInt(); xr.ReadEndElement(/* Agent */); } header.Technician = new List<string>(); while (xr.Name == "Technician") { xr.ReadStartElement(/* Technician */); header.Technician.Add(xr.ReadContentAsString()); xr.ReadEndElement(/* Technician */); } if (xr.Name == "Other") { header.OtherSessionInfo = new Dictionary<string, string>(); do { string name = xr["Name"]; xr.ReadStartElement(/* Other */); string value = xr.ReadContentAsString(); xr.ReadEndElement(/* Other */); header.OtherSessionInfo.Add(name, value); } while (xr.Name == "Other"); } xr.ReadStartElement("BDFFile", nameSpace); header.BDFFile = xr.ReadContentAsString(); xr.ReadEndElement(/* BDFFile */); xr.ReadStartElement("EventFile", nameSpace); header.EventFile = xr.ReadContentAsString(); xr.ReadEndElement(/* EventFile */); xr.ReadStartElement("ElectrodeFile", nameSpace); header.ElectrodeFile = xr.ReadContentAsString(); xr.ReadEndElement(/* ElectrodeFile */); if (xr.Name == "Comment") { xr.ReadStartElement(/* Comment */); header.Comment = xr.ReadContentAsString(); //Optional comment xr.ReadEndElement(/* Comment */); } xr.ReadEndElement(/* SessionDescription */); return header; } catch (Exception e) { XmlNodeType nodeType = xr.NodeType; string name = xr.Name; throw new Exception("HeaderFileReader.read: Error processing " + nodeType.ToString() + " named " + name + ": " + e.Message); } }
public MainWindow() { Log.writeToLog("Starting DatasetReviewer " + Assembly.GetExecutingAssembly().GetName().Version.ToString()); do { bool r; do { System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog(); dlg.Title = "Open Header file to be displayed..."; dlg.DefaultExt = ".hdr"; // Default file extension dlg.Filter = "HDR Files (.hdr)|*.hdr"; // Filter files by extension bool result = dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK; if (!result) Environment.Exit(0); directory = System.IO.Path.GetDirectoryName(dlg.FileName); //will use to find other files in dataset headerFileName = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName); try { head = (new HeaderFileReader(dlg.OpenFile())).read(); } catch (Exception e) { r = false; //loop around again ErrorWindow ew = new ErrorWindow(); ew.Message = "Error reading Header file: " + e.Message; continue; } ED = head.Events; try { bdf = new BDFEDFFileStream.BDFEDFFileReader( new FileStream(System.IO.Path.Combine(directory, head.BDFFile), FileMode.Open, FileAccess.Read)); } catch (Exception e) { r = false; //loop around again ErrorWindow ew = new ErrorWindow(); ew.Message = "Error reading BDF file header: " + e.Message; ew.ShowDialog(); continue; } BDFLength = (double)bdf.NumberOfRecords * bdf.RecordDurationDouble; Window1 w = new Window1(this); r = (bool)w.ShowDialog(); } while (r == false); Log.writeToLog(" on dataset " + headerFileName); if (includeANAs) { foreach (EventDictionaryEntry ede in ED.Values) // add ANA channels that are referenced by extrinsic Events { if (ede.IsCovered && ede.IsExtrinsic) { int chan = bdf.ChannelNumberFromLabel(ede.channelName); if (!channelList.Contains(chan)) //don't enter duplicate channelList.Add(chan); } } } } while (channelList.Count == 0); InitializeComponent(); //initialize the individual channel graphs foreach (int i in channelList) { ChannelGraph pg = new ChannelGraph(this, i); GraphCanvas.Children.Add(pg); } Title = headerFileName; //set window title BDFFileInfo.Content = bdf.ToString(); HDRFileInfo.Content = head.ToString(); Event.EventFactory.Instance(head.Events); // set up the factory EventFileReader efr = null; try { efr = new EventFileReader( new FileStream(System.IO.Path.Combine(directory, head.EventFile), FileMode.Open, FileAccess.Read)); // open Event file bool z = false; foreach (Event.InputEvent ie in efr)// read in all Events into dictionary { if (ie.IsNaked) events.Add(ie); else if (events.Count(e => e.GC == ie.GC) == 0) //quietly skip duplicates { if (!z) //use first found covered Event to synchronize clocks z = bdf.setZeroTime(ie); events.Add(ie); } } efr.Close(); //now events is Dictionary of Events in the dataset; lookup by GC } catch (Exception e) { ErrorWindow ew = new ErrorWindow(); ew.Message = "Error reading Event file : " + e.Message + ". Exiting DatasetReviewer."; ew.ShowDialog(); Log.writeToLog(Environment.NewLine + e.StackTrace); Environment.Exit(0); } try { ElectrodeInputFileStream eif = new ElectrodeInputFileStream( new FileStream(System.IO.Path.Combine(directory, head.ElectrodeFile), FileMode.Open, FileAccess.Read)); //open Electrode file electrodes = eif.etrPositions; //read 'em in } catch (Exception e) { ErrorWindow ew = new ErrorWindow(); ew.Message = "Error reading Electrode file : " + e.Message + ". Exitting DatasetReviewer."; ew.ShowDialog(); Log.writeToLog(Environment.NewLine + e.StackTrace); Environment.Exit(0); } EventMarkers.Width = BDFLength; eventTB = new TextBlock(new Run("Events")); Canvas.SetBottom(eventTB, ScrollBarSize + 13D); //initialize gridline array for (int i = 0; i < 18; i++) { Line l = new Line(); Grid.SetRow(l, 0); Grid.SetColumn(l, 0); Grid.SetColumnSpan(l, 2); l.Y1 = 0D; l.HorizontalAlignment = HorizontalAlignment.Left; l.VerticalAlignment = VerticalAlignment.Stretch; l.IsHitTestVisible = false; l.Stroke = Brushes.LightBlue; l.Visibility = Visibility.Hidden; Panel.SetZIndex(l, int.MinValue); MainFrame.Children.Add(l); gridlines[i] = l; } //Initialize timer timer.AutoReset = true; timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); //Initialize channel information popup Color c1 = Color.FromArgb(0xFF, 0xF8, 0xF8, 0xF8); Color c2 = Color.FromArgb(0xFF, 0xC8, 0xC8, 0xC8); popupTB.Background = new LinearGradientBrush(c1, c2, 45D); popupTB.Foreground = Brushes.Black; popupTB.Padding = new Thickness(4D); Border b = new Border(); b.BorderThickness = new Thickness(1); b.CornerRadius = new CornerRadius(4); b.BorderBrush = Brushes.Tomato; b.Margin = new Thickness(0, 0, 24, 24); //allows drop shadow to show up b.Effect = new DropShadowEffect(); b.Child = popupTB; channelPopup.Placement = PlacementMode.MousePoint; channelPopup.AllowsTransparency = true; channelPopup.Child = b; //Initialize Event information popup eventPopupTB.Background = new LinearGradientBrush(c1, c2, 45D); eventPopupTB.Foreground = Brushes.Black; eventPopupTB.Padding = new Thickness(4D); b = new Border(); b.BorderThickness = new Thickness(1); b.CornerRadius = new CornerRadius(4); b.BorderBrush = Brushes.Tomato; b.Margin = new Thickness(0, 0, 24, 24); //allows drop shadow to show up b.Effect = new DropShadowEffect(); b.Child = eventPopupTB; eventPopup.Placement = PlacementMode.MousePoint; eventPopup.AllowsTransparency = true; eventPopup.Child = b; //Initialize FOV slider FOV.Maximum = Math.Log10(BDFLength); FOV.Value = 1D; FOVMax.Text = BDFLength.ToString("0"); //Initialize Event selector bool first = true; foreach (EventDictionaryEntry e in head.Events.Values) { MenuItem mi = (MenuItem)EventSelector.FindResource("EventMenuItem"); mi.Header = e.Name; if (first) { mi.IsChecked = true; first = false; } EventSelector.Items.Add(mi); } noteFilePath = System.IO.Path.Combine(directory,System.IO.Path.ChangeExtension(head.BDFFile,".notes.txt")); //from here on the program is GUI-event driven }
public HeaderFileWriter(Stream str, Header.Header head) { try { if (str == null) return; if (!str.CanWrite) throw new IOException("unable to write to stream"); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.CloseOutput = true; settings.Encoding = Encoding.UTF8; settings.CheckCharacters = true; xw = XmlWriter.Create(str, settings); xw.WriteStartDocument(); xw.WriteStartElement("Header"); xw.WriteStartElement("ExperimentDescription"); xw.WriteElementString("SoftwareVersion", head.SoftwareVersion); xw.WriteElementString("Title", head.Title); xw.WriteElementString("LongDescription", head.LongDescription); foreach (string s in head.Experimenter) xw.WriteElementString("Experimenter", s); xw.WriteElementString("Status", head.Status.ToString("0")); if (head.OtherExperimentInfo != null) foreach (KeyValuePair<string, string> other in head.OtherExperimentInfo) { xw.WriteStartElement("Other"); xw.WriteAttributeString("Name", other.Key); xw.WriteString(other.Value); xw.WriteEndElement(/* Other */); } foreach (GroupVarDictionary.GVEntry gve in head.GroupVars.Values) { xw.WriteStartElement("GroupVar"); xw.WriteElementString("Name", gve.Name); xw.WriteElementString("Description", gve.Description); if(gve.GVValueDictionary != null) // will be null if integer values just stand for themselves foreach (KeyValuePair<string, int> i in gve.GVValueDictionary) { xw.WriteStartElement("GV"); xw.WriteAttributeString("Desc", i.Key); xw.WriteString(i.Value.ToString("0")); xw.WriteEndElement(/* GV */); } xw.WriteEndElement(/* GroupVar */); } foreach (KeyValuePair<string, EventDictionaryEntry> ede in head.Events) { xw.WriteStartElement("Event"); xw.WriteAttributeString("Type", ede.Value.IsCovered ? (bool)ede.Value.intrinsic ? "intrinsic" : "extrinsic" : "*"); xw.WriteAttributeString("Clock", ede.Value.BDFBased ? "BDF-based" : "Absolute"); xw.WriteElementString("Name", ede.Key); xw.WriteElementString("Description", ede.Value.Description); if (ede.Value.IsCovered && !(bool)ede.Value.intrinsic) { xw.WriteElementString("Channel", ede.Value.channelName); xw.WriteElementString("Edge", ede.Value.rise ? "rising" : "falling"); xw.WriteElementString("Location", ede.Value.location ? "after" : "before"); if (ede.Value.channelMax != 0) xw.WriteElementString("Max", ede.Value.channelMax.ToString("G")); if (ede.Value.channelMin != 0) xw.WriteElementString("Min", ede.Value.channelMin.ToString("G")); } if (ede.Value.ancillarySize != 0) xw.WriteElementString("Ancillary", ede.Value.ancillarySize.ToString("0")); if(ede.Value.GroupVars!=null) foreach (GVEntry gv in ede.Value.GroupVars) { xw.WriteStartElement("GroupVar", ""); xw.WriteAttributeString("Name", gv.Name); xw.WriteEndElement(/* GroupVar */); } xw.WriteEndElement(/* Event */); } xw.WriteEndElement(/* ExperimentDescription */); xw.WriteStartElement("SessionDescription"); xw.WriteElementString("Date", head.Date); xw.WriteElementString("Time", head.Time); xw.WriteElementString("Subject", head.Subject.ToString("0000")); xw.WriteElementString("Agent", head.Agent.ToString("0000")); foreach (string tech in head.Technician) xw.WriteElementString("Technician", tech); if(head.OtherSessionInfo != null) foreach (KeyValuePair<string, string> other in head.OtherSessionInfo) { xw.WriteStartElement("Other"); xw.WriteAttributeString("Name", other.Key); xw.WriteString(other.Value); xw.WriteEndElement(/* Other */); } xw.WriteElementString("BDFFile", head.BDFFile); xw.WriteElementString("EventFile", head.EventFile); xw.WriteElementString("ElectrodeFile", head.ElectrodeFile); if (head.Comment != null && head.Comment != "") xw.WriteElementString("Comment", head.Comment); xw.WriteEndElement(/* SessionDescription */); xw.WriteEndElement(/* Header */); xw.Close(); } catch (Exception x) { throw new Exception("HeaderFileWriter: " + x.Message); } }