1function viewedf(Action, ActOption)
2% viewedf
3% Display EDF (European Data Format) files
4% This program requires Matlab Version >= 5.2 and should work with Matlab 6.x
5%
6% Command line functionality (note: all commands are case sensitive):
7% viewedf : start program
8% viewedf('OpenEDFFile', FILENAME) : open FILENAME
9% viewedf('Goto', RECORD) : move to RECORD
10% viewedf('GotoSecond', SECOND) : move to a certain SECOND
11% viewedf('Prev') : move back one screen
12% viewedf('Next') : move forward one screen
13% viewedf('PrevFast') : move back 5 screens
14% viewedf('NextFast') : move forward 5 screens
15% viewedf('Close') : close viewer
16%
17% Keyboard shortcuts:
18% '+' : move to next screen
19% '-' : move to previous screen
20% 'U' : scale all channels up
21% 'D' : scale all channels down
22%
23% Version 3.04Alpha, 10/22/01
24% (c) Herbert Ramoser (herbert.ramoser@arcs.ac.at)
25%
26% This Software is subject to the GNU public license v2 or later.
27
28%	$Id: sopen.m 2529 2010-09-06 23:32:46Z schloegl $
29%    	This is part of the BIOSIG-toolbox http://biosig.sf.net/
30%
31%    BioSig is free software: you can redistribute it and/or modify
32%    it under the terms of the GNU General Public License as published by
33%    the Free Software Foundation, either version 2 of the License, or
34%    (at your option) any later version.
35%
36%    BioSig is distributed in the hope that it will be useful,
37%    but WITHOUT ANY WARRANTY; without even the implied warranty of
38%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39%    GNU General Public License for more details.
40%
41%    You should have received a copy of the GNU General Public License
42%    along with BioSig.  If not, see <http://www.gnu.org/licenses/>.
43
44
45% Changes:
46% 01/27/98 Ramoser: Plugins may replace EDF data, optional parameter string
47%   is passed to the plugin
48% 01/30/98 Ramoser: plotting of EDF.Valid information
49% 02/02/98 Ramoser: print option added
50% 02/18/98 Ramoser: Stairplot-feature added, bug for hypnograms removed
51% 06/16/98 Ramoser: bugs of Matlab 5.2 fixed (return, inputdlg)
52%          display multiple EDF files
53%          fixed order of channels
54%          export of matrices to workspace
55%          increase in plotting speed
56% 09/18/98 Ramoser: new EDF open and read functions included
57%          upside down display of plots
58%          use of cell arrays to store EDF data
59%          data passed to plugins has changed
60% 11/01/98 Woertz: reset display after calls of plugin menus
61% 11/23/98 Ramoser: give only one file to plugin
62%          handling of plugins when EDF files are closed
63% 11/30/98 Ramoser: GDF functionality added
64% 12/02/98 Ramoser: optionally display plot Y tick-labels
65% 12/03/98 Ramoser: fixed dialog boxes under X (drawnow added)
66%          upside-down plotting bug removed
67% 12/07/98 Ramoser: scaling buttons added
68% 12/09/98 Ramoser: physical dimension added to Y-label
69% 02/18/99 Ramoser: problems with multiple files, multiple record lengths
70%          and scrollbar removed
71% 03/04/99 Ramoser: Assign matrix - plugin bug removed
72% 03/26/99 Ramoser: GDF 0.12 added, set properties of all channels
73%          simultaneusly ('Apply to all' button)
74% 03/31/99 Ramoser: time tracking line added
75% 04/01/99 Ramoser: print problems resolved
76% 04/29/99 Ramoser: do not reset display properties after a call to
77%          plugin-menu
78% 05/04/99 Ramoser: time tracking line bugs removed
79% 05/12/99 Ramoser: file positioning information added (EDFHead.AS.startrec
80%          & numrec)
81% 03/17/00 Ramoser: add command line functionality, add 'Goto second'
82% 10/22/01 Ramoser: some updates for Matlab 6
83% 01 Sep 2008 Schloegl: use sopen, sclose
84% Jun 2010 Alois Schloegl
85
86FastPageIncrement = 5;
87PageIncrement = 1;
88warning('off');
89
90switch nargin,
91 case 0,
92  if ~isempty(findobj('Tag', 'ViewEDFFigure'))
93    error('Only one copy of VIEWEDF may be run');
94  end
95  LocalInitWindow;
96 case 1,
97  switch Action
98   case 'OpenEDFFile',
99    LocalEDFOpen;
100   case 'CloseEDFFile',
101    LocalEDFClose;
102   case 'Repaint'
103    LocalRepaint;
104   case 'AddPlugin'
105    LocalAddPlugin;
106   case 'RemovePlugin'
107    LocalRemovePlugin;
108   case 'PluginMenu'
109    LocalPluginMenu;
110   case 'PrevFast'
111    LocalChangeRecord(-FastPageIncrement,0);
112   case 'Prev'
113    LocalChangeRecord(-PageIncrement,0);
114   case 'NextFast'
115    LocalChangeRecord(FastPageIncrement,0);
116   case 'Next'
117    LocalChangeRecord(PageIncrement,0);
118   case 'HScroll'
119    LocalHScroll;
120   case 'ToggleUpdatePlugin'
121    LocalToggleUpdatePlugin;
122   case 'ToggleShowRange'
123    LocalToggleShowRange;
124   case 'ToggleShowCursor'
125    LocalToggleShowCursor;
126   case 'RecordProp'
127    LocalRecordProp;
128   case 'Goto'
129    LocalGotoRecord;
130   case 'GotoSecond'
131    LocalGotoSecond;
132   case 'Records'
133    LocalNumRecords;
134   case 'FileInfo'
135    LocalFileInfo;
136   case 'Channels'
137    LocalSelectChannels;
138   case 'About'
139    LocalAbout;
140   case 'Help'
141    LocalHelp;
142   case 'KeyPress'
143    LocalKeyPress;
144   case 'Print'
145    LocalPrint;
146   case 'AssignMat'
147    LocalAssignMat;
148   case 'ScaleUp'
149    LocalRescale('up');
150   case 'ScaleDown'
151    LocalRescale('down');
152   case 'Close'
153    LocalCloseViewEDF;
154   otherwise
155    error('VIEWEDF must be called without parameters');
156  end
157 case 2,
158  switch Action
159   case 'OpenEDFFile',
160    LocalEDFOpen(ActOption);
161   case 'FileInfo'
162    LocalFileInfo(ActOption);
163   case 'Channels'
164    LocalSelectChannels(ActOption);
165   case 'MoveCursor'
166    LocalMoveCursor(ActOption);
167   case 'Goto'
168    LocalGotoRecord(ActOption);
169   case 'GotoSecond'
170    LocalGotoSecond(ActOption);
171   otherwise
172    error('Unknown argument!');
173  end
174 otherwise
175  error('Unknown argument!');
176end
177
178%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
179% LocalInitWindow
180% initializes the window (display buttons, ...)
181function LocalInitWindow()
182
183args = { 'NumberTitle', 'off', ...
184    'CloseRequestFcn', 'viewedf Close', ...
185    'IntegerHandle', 'off', ...
186    'KeyPressFcn', 'viewedf KeyPress', ...
187    'MenuBar', 'none', ...
188    'Color', [0.9, 0.9, 0.9], ...
189    'ResizeFcn', 'viewedf Repaint', ...
190    'Tag', 'ViewEDFFigure', ...
191    'Name', 'EDF File Viewer - (C) 1998-2001 DPMI, 2008 HCI, Graz University of Technology; 2010 Alois Schloegl'
192    };
193if ~exist('OCTAVE_VERSION','builtin')
194    args = {args{:}, ...
195    'Units', 'Normalized', ...
196    'PaperPositionMode', 'Auto', ...
197    'PaperType', 'A4', ...
198    'PaperUnits', 'Normalized', ...
199    };
200end;
201
202fig=figure(args{:});
203
204Data=get(fig,'UserData');
205
206% Menus
207mh = uimenu('Label', '&File');
208uimenu(mh, ...
209    'Label', '&Open EDF', ...
210    'Callback', 'viewedf OpenEDFFile');
211uimenu(mh, ...
212    'Label', '&Close EDF', ...
213    'Callback', 'viewedf CloseEDFFile');
214uimenu(mh, ...
215    'Label', '&Add Plugin', ...
216    'Callback', 'viewedf AddPlugin');
217uimenu(mh, ...
218    'Label', '&Remove Plugin', ...
219    'Callback', 'viewedf RemovePlugin');
220uimenu(mh, ...
221    'Label', '&Print', ...
222    'Separator', 'on', ...
223    'Callback', 'viewedf Print');
224uimenu(mh, ...
225    'Label', 'Assign &Matrix', ...
226    'Callback', 'viewedf AssignMat');
227uimenu(mh, ...
228    'Label', 'E&xit', ...
229    'Separator', 'on', ...
230    'Callback', 'viewedf Close');
231
232mh = uimenu('Label', '&Display');
233uimenu(mh, ...
234    'Label', 'File &info', ...
235    'Callback', 'viewedf FileInfo');
236uimenu(mh, ...
237    'Label', '&Goto Record', ...
238    'Callback', 'viewedf Goto');
239uimenu(mh, ...
240    'Label', '&Goto Second', ...
241    'Callback', 'viewedf GotoSecond');
242uimenu(mh, ...
243    'Label', '&Records on Screen', ...
244    'Callback', 'viewedf Records');
245uimenu(mh, ...
246    'Label', '&Channels', ...
247    'Callback', 'viewedf Channels');
248
249mh = uimenu('Label', '&Options');
250uimenu(mh, ...
251    'Label', '&Update Plugin', ...
252    'Checked', 'on', ...
253    'Callback', 'viewedf ToggleUpdatePlugin');
254uimenu(mh, ...
255    'Label', 'Show &Range', ...
256    'Checked', 'off', ...
257    'Callback', 'viewedf ToggleShowRange');
258uimenu(mh, ...
259    'Label', 'Show &Cursor', ...
260    'Checked', 'off', ...
261    'Callback', 'viewedf ToggleShowCursor');
262Data.Display.PluginMenu.Main = uimenu(mh, ...
263    'Label', '&Plugin');
264
265mh = uimenu('Label', '&?');
266uimenu(mh, ...
267    'Label', '&Help', ...
268    'CallBack', 'viewedf Help');
269uimenu(mh, ...
270    'Label', '&About', ...
271    'CallBack', 'viewedf About');
272
273% Strings
274textx = 0.02;
275textheight = LocalGetFontHeight();
276texty = 1 - textheight / 4;
277Data.Display.Strings.CurrTime = uicontrol(fig, ... % Time string
278    'Style', 'Text', ...
279    'Units', 'Normalized', ...
280    'String', '', ...
281    'HorizontalAlignment', 'left', ...
282    'FontUnits', 'normalized', ...
283    'Position', [textx, texty - textheight, 0.2, ...
284      textheight]);
285Data.Display.Strings.TotTime = uicontrol(fig, ... % Total time string
286    'Style', 'Text', ...
287    'Units', 'Normalized', ...
288    'String', 'Total length : ', ...
289    'HorizontalAlignment', 'left', ...
290    'Position', [textx, texty - textheight, 0.2, ...
291      textheight]);
292Data.Display.Strings.DispTime = uicontrol(fig, ... % Displayed time stretch string
293    'Style', 'Text', ...
294    'Units', 'Normalized', ...
295    'String', 'Displayed : ', ...
296    'HorizontalAlignment', 'left', ...
297    'Position', [textx + 0.22, texty - textheight, 0.2, ...
298      textheight]);
299Data.Display.Strings.FileName = uicontrol(fig, ... % File string
300    'Style', 'Text', ...
301    'Units', 'Normalized', ...
302    'String', 'File : ', ...
303    'HorizontalAlignment', 'left', ...
304    'Position', [textx + 0.44, texty - textheight, 0.2, ...
305      textheight]);
306Data.Display.Strings.NumString = 4;
307
308% Build data structure
309% settings for the display (where to plot things, ...)
310Data.Display.Axes = [];       % nothing to display
311Data.Display.YSpacing = 0.0025;   % spacing between plots
312Data.EDF = [];
313Data.Plugin = [];
314Data.UpdatePlugin = 1;
315Data.ShowRange = 0;
316Data.ShowCursor = 0;
317Data.Display.Cursor = [];
318set(fig,'UserData',Data);
319drawnow;
320
321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322% LocalResetDisplay
323% reset display variables
324function LocalResetDisplay()
325Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
326if length(Data.EDF)==0
327  return;
328end
329%EDF data
330MaxDur = max(LocalGetEDFInfo('Dur', Data.EDF));
331for i=1:length(Data.EDF)
332  Data.Display.EDF(i).ShowRecords = [0, round(MaxDur / Data.EDF(i).Head.Dur)];
333  [Data.EDF(i).Record, Data.EDF(i).Head] = ...
334      LocalEDFRead(Data.EDF(i).Head, Data.Display.EDF(i).ShowRecords);
335  Data.Display.EDF(i).ShowSignals = 1:Data.EDF(i).Head.NS;
336  Data.Display.EDF(i).DisplayMin = Data.EDF(i).Head.PhysMin;
337  Data.Display.EDF(i).DisplayMax = Data.EDF(i).Head.PhysMax;
338  Data.Display.EDF(i).StairPlot = zeros(1, Data.EDF(i).Head.NS);
339  Data.Display.EDF(i).UpDownPlot = Data.EDF(i).Head.PhysMin>Data.EDF(i).Head.PhysMax; %zeros(1, Data.EDF(i).Head.NS);
340end
341
342% Plugin data
343for i = 1:length(Data.Plugin)
344  [Data.Plugin(i).EDF, Data.Plugin(i).UserData] = ...
345      feval(Data.Plugin(i).Name, Data.EDF(1), Data.Plugin(i).UserData, ...
346      'Reset');
347  Data.Display.Plugin(i).ShowRecords = [0, round(MaxDur / Data.Plugin(i).Head.Dur)];
348  Data.Display.Plugin(i).ShowSignals = 1:Data.Plugin(i).Head.NS;
349  Data.Display.Plugin(i).DisplayMin = Data.Plugin(i).EDF.Head.PhysMin;
350  Data.Display.Plugin(i).DisplayMax  = ...
351      Data.Plugin(i).EDF.Head.PhysMax;
352  Data.Display.Plugin(i).StairPlot = zeros(1, Data.Plugin(i).Head.NS);
353  Data.Display.Plugin(i).UpDownPlot = Data.EDF(i).Head.PhysMin>Data.EDF(i).Head.PhysMax; %zeros(1, Data.Plugin(i).Head.NS);
354end
355
356% update all strings
357tsec = max(LocalGetEDFInfo('FileDur', Data.EDF));
358tmin = floor(tsec/60);
359tsec = rem(tsec,60);
360th = floor(tmin/60);
361tmin = rem(tmin,60);
362set(Data.Display.Strings.TotTime, 'String', ...
363  sprintf('Total length : %02d:%02d:%02d', th,tmin,tsec));
364fname = 'File : ';
365% add '+' for additional files
366for i = 1:(length(Data.EDF) - 1)
367  fname = [fname Data.EDF(i).Head.FILE.Name '.' Data.EDF(i).Head.FILE.Ext ...
368        ' + '];
369end
370fname = [fname Data.EDF(end).Head.FILE.Name '.' Data.EDF(end).Head.FILE.Ext];
371set(Data.Display.Strings.FileName, 'String', fname);
372set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
373LocalRepaint(0);
374
375%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376% LocalRepaint
377% initializes the window (display buttons, ...)
378function LocalRepaint(KeepOldPlots)
379figure(findobj('Tag', 'ViewEDFFigure'));
380Data = get(gcf, 'UserData');
381fhght = LocalGetFontHeight;
382if length(Data.EDF)==0
383  return;
384end
385if nargin < 1
386  KeepOldPlots = 0;
387end
388KeepOldPlots = (KeepOldPlots ~= 0);
389
390% set display size (area left for plots)
391Data.Display.DrawRect = [0.005 1.5*fhght 0.85 1-1.5*fhght];
392
393% get width of figure
394unit = get(gcf, 'Units');
395set(gcf, 'Units', 'Pixels');
396xpix = get(gcf, 'Position');
397set(gcf, 'Units', unit);
398xpix = xpix(3);
399
400% calculate total number of plots
401TotPlots = 0;
402for i=1:length(Data.EDF)
403  TotPlots = TotPlots + length(Data.Display.EDF(i).ShowSignals);
404end
405for i=1:length(Data.Plugin)
406  TotPlots = TotPlots + length(Data.Display.Plugin(i).ShowSignals);
407end
408
409% update plugin-data
410LocalWatchOn;
411if Data.UpdatePlugin || ~KeepOldPlots,
412  for i = 1:length(Data.Plugin)
413    [Data.Plugin(i).EDF, Data.Plugin(i).UserData] = ...
414        feval(Data.Plugin(i).Name, Data.EDF(Data.Plugin(i).EDFFile), ...
415        Data.Plugin(i).UserData);
416  end
417end
418LocalWatchOff;
419
420Opt.YSpace = Data.Display.YSpacing;
421Opt.TxtHeight = fhght;
422Opt.TextWidth = 1 - Data.Display.DrawRect(3) - Data.Display.DrawRect(1) - ...
423    0.01;
424Opt.TextX = Data.Display.DrawRect(1) + Data.Display.DrawRect(3) + 0.005;
425Opt.ButHeight = Opt.TxtHeight * 1.2;
426Opt.ValidHeight = 0.005;
427Opt.FigX = Data.Display.DrawRect(1);
428Opt.FigWidth = Data.Display.DrawRect(3);
429if Data.ShowRange
430  Opt.LabelWidth = min([0.1, 4*LocalGetFontWidth]);
431else
432  Opt.LabelWidth = 0;
433end
434Opt.FigY = Data.Display.DrawRect(2) + Data.Display.DrawRect(4) - ...
435    1.5*Opt.TxtHeight - Opt.ValidHeight;
436Opt.FigHeight = (Data.Display.DrawRect(4) - 1.5*Opt.TxtHeight - ...
437    Opt.ValidHeight)  / TotPlots - Opt.YSpace;
438Opt.TxtHeight = min([(Opt.FigHeight-Opt.YSpace)/2, Opt.TxtHeight]);
439Opt.ButHeight = min([(Opt.FigHeight-Opt.YSpace)/2, Opt.ButHeight]);
440Opt.XPixels = 4*xpix;
441Opt.ShowRange = Data.ShowRange;
442
443% clear old buttons and labels
444if ~KeepOldPlots && ~isempty(Data.Display.Axes),
445  delete(Data.Display.HScrollBar);
446  if ~isempty(Data.Display.Cursor);
447    delete(Data.Display.Cursor.Line(:));
448    delete(Data.Display.Cursor.Menu.Text);
449    delete(Data.Display.Cursor.Menu.Menu);
450    Data.Display.Cursor = [];
451  end
452  delete(Data.Display.Axes(:).RecButton);
453  delete(Data.Display.Axes(:).ScaleUpButton);
454  delete(Data.Display.Axes(:).ScaleDownButton);
455  delete(Data.Display.Axes(:).RecLabel);
456  delete(Data.Display.Axes(:).MaxLabel);
457  delete(Data.Display.Axes(:).MinLabel);
458  delete(Data.Display.Axes(:).DimLabel);
459  delete(Data.Display.Axes(:).PlotLine);
460  delete(Data.Display.Axes(:).Plot);
461  Data.Display.Axes = [];
462end
463
464% draw HScrollBar
465FileDur = LocalGetEDFInfo('FileDur',Data.EDF);
466[MaxVal, MFInd] = max(FileDur);
467Dur = LocalGetEDFInfo('Dur', Data.EDF);
468[MaxDur, MDInd] = max(Dur);
469Len = Data.Display.EDF(MFInd).ShowRecords(1);
470if ~KeepOldPlots
471  Data.Display.HScrollBar = uicontrol(gcf, ...
472      'Style', 'Slider', ...
473      'Units', 'Normalized', ...
474      'Position', [Data.Display.DrawRect(1), 0, ...
475        Data.Display.DrawRect(3), LocalGetFontHeight], ...
476      'SliderStep', [MaxDur/MaxVal 5*MaxDur/MaxVal] * ...
477      Data.Display.EDF(MDInd).ShowRecords(2), ...
478      'Min', 0, ...
479      'Max', 1, ...
480      'Value', Data.Display.EDF(MFInd).ShowRecords(1)/MaxVal*Dur(MFInd), ...
481      'CallBack', 'viewedf HScroll');
482else
483  set(Data.Display.HScrollBar, ...
484      'Value', Data.Display.EDF(MFInd).ShowRecords(1)/MaxVal*Dur(MFInd));
485end
486
487%create new buttons, plots and labels
488cnt = 0;
489for j=1:length(Data.EDF)
490  for i=1:length(Data.Display.EDF(j).ShowSignals)
491    cnt = cnt+1;
492    showsig = Data.Display.EDF(j).ShowSignals(i);
493    if ~KeepOldPlots
494      % make new plots, buttons, labels
495      Opt.YPos = Opt.FigY - Opt.YSpace*(cnt-1) - Opt.FigHeight * cnt;
496      Opt.DisplayMin = Data.Display.EDF(j).DisplayMin(showsig);
497      Opt.DisplayMax = Data.Display.EDF(j).DisplayMax(showsig);
498      Opt.UserData = { 'EDF', showsig, j};
499      Opt.Label = Data.EDF(j).Head.Label(showsig,:);
500      %Opt.YLabel = deblank(Data.EDF(j).Head.PhysDim(showsig,:));
501      Opt.YLabel = deblank(Data.EDF(j).Head.PhysDim{showsig});
502      yd = Data.EDF(j).Record{showsig};
503      if (length(yd) ~= 1)
504        yd = [yd(:); NaN];
505      end
506
507      Temp = ...
508          LocalPlotNewData(yd, ...
509          Data.Display.EDF(j).UpDownPlot(showsig), ...
510          Data.Display.EDF(j).StairPlot(showsig), Opt);
511      if cnt == 1
512          Data.Display.Axes = Temp;
513      else
514          Data.Display.Axes(cnt) = Temp;
515      end
516    else
517      % set new ydata
518      yd = Data.EDF(j).Record{showsig} * ...
519          (Data.Display.EDF(j).UpDownPlot(showsig)-0.5) * -2;
520      if (length(yd) == 1)
521        yd = yd([1 1]);
522      else
523        yd = yd(1:ceil(length(yd)/Opt.XPixels):length(yd));
524        yd = [yd(:); NaN];
525        if Data.Display.EDF(j).StairPlot(showsig)
526          yd = yd(floor(1:0.5:length(yd)));
527        end
528      end
529      set(Data.Display.Axes(cnt).PlotLine, 'YData', yd);
530    end
531  end
532end
533
534% plot plugin-data
535for j = 1:length(Data.Plugin)
536  for i=1:length(Data.Display.Plugin(j).ShowSignals)
537    cnt = cnt+1;
538    showsig = Data.Display.Plugin(j).ShowSignals(i);
539    if ~KeepOldPlots
540      % make new plots, buttons, labels
541      Opt.YPos = Opt.FigY - Opt.YSpace*(cnt-1) - Opt.FigHeight * cnt;
542      Opt.DisplayMin = Data.Display.Plugin(j).DisplayMin(showsig);
543      Opt.DisplayMax = Data.Display.Plugin(j).DisplayMax(showsig);
544      Opt.UserData = { 'PLUGIN', showsig, j};
545      Opt.Label = Data.Plugin(j).EDF.Head.Label(showsig,:);
546      %Opt.YLabel = deblank(Data.Plugin(j).EDF.Head.PhysDim(showsig,:));
547      Opt.YLabel = deblank(Data.Plugin(j).EDF.Head.PhysDim{showsig});
548      yd = Data.Plugin(j).EDF.Record{showsig};
549      if (length(yd) ~= 1)
550        yd = [yd(:); NaN];
551      end
552      Data.Display.Axes(cnt) = ...
553          LocalPlotNewData(yd, ...
554          Data.Display.Plugin(j).UpDownPlot(showsig), ...
555          Data.Display.Plugin(j).StairPlot(showsig), Opt);
556    else
557      yd = Data.Plugin(j).EDF.Record{showsig} * ...
558          (Data.Display.Plugin(j).UpDownPlot(showsig)-0.5) * -2;
559      if (length(yd) == 1)
560        yd = yd([1 1]);
561      else
562        yd = yd(1:ceil(length(yd)/Opt.XPixels):length(yd));
563        yd = [yd(:); NaN];
564        if Data.Display.Plugin(j).StairPlot(showsig)
565          yd = yd(floor(1:0.5:length(yd)));
566        end
567      end
568      set(Data.Display.Axes(cnt).PlotLine, 'YData', yd);
569    end
570  end
571end
572
573% change size of all strings
574set(Data.Display.Strings.CurrTime, ...
575    'Position', [Opt.TextX, 0, Opt.TextWidth, fhght]);
576pos = get(Data.Display.Strings.TotTime, 'Position');
577set(Data.Display.Strings.TotTime, ...
578    'Position', [pos(1), 1 - 1.25 * fhght, pos(3), fhght]);
579pos = get(Data.Display.Strings.DispTime, 'Position');
580set(Data.Display.Strings.DispTime, ...
581    'Position', [pos(1), 1 - 1.25 * fhght, pos(3), fhght]);
582pos = get(Data.Display.Strings.FileName, 'Position');
583ext = get(Data.Display.Strings.FileName, 'Extent');
584set(Data.Display.Strings.FileName, ...
585    'Position', [pos(1), 1 - 1.25 * fhght, ext(3) + 0.01, fhght]);
586
587% change size of HScrollBar
588pos = get(Data.Display.HScrollBar, 'Position');
589set(Data.Display.HScrollBar, ...
590    'Position', [pos(1) pos(2) pos(3) fhght]);
591
592% draw cursor
593if Data.ShowCursor && ~KeepOldPlots,
594  Data.Display.Cursor = LocalDrawCursor(Data.Display);
595end
596
597% display time
598tsec = Data.EDF(1).Head.Dur * Data.Display.EDF(1).ShowRecords(1);
599tmin = floor(tsec/60);
600tsec = rem(tsec,60);
601th = floor(tmin/60);
602tmin = rem(tmin,60);
603set(Data.Display.Strings.CurrTime, 'String', ...
604    sprintf('Time %02d:%02d:%02d', th,tmin,tsec));
605tsec = Data.EDF(1).Head.Dur * Data.Display.EDF(1).ShowRecords(2);
606tmin = floor(tsec/60);
607tsec = rem(tsec,60);
608th = floor(tmin/60);
609tmin = rem(tmin,60);
610set(Data.Display.Strings.DispTime, 'String', ...
611    sprintf('Displayed : %02d:%02d:%02d', th,tmin,tsec));
612set(gcf, 'UserData', Data);
613drawnow;
614
615%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616% LocalPlotNewData
617% plots a single data vector
618function [ploth] =  LocalPlotNewData(Data, UpDownPlot, StairPlot, Opt)
619len = length(Data);
620ploth.Plot = subplot('Position', ...
621    [Opt.FigX + Opt.LabelWidth, Opt.YPos, Opt.FigWidth - Opt.LabelWidth, ...
622      Opt.FigHeight - Opt.YSpace]);
623if (len == 1)
624  xd = [1 2];
625  yd = Data([1 1]);
626else
627  yd = Data(1:ceil(len/Opt.XPixels):len);
628  len = length(yd);
629  if StairPlot
630    xd = ceil(1:0.5:len);
631    yd = yd(floor(1:0.5:len));
632  else
633    xd = 1:len;
634  end
635end
636
637if UpDownPlot
638  yd = yd * -1;
639  tmp = Opt.DisplayMin;
640  Opt.DisplayMin = -Opt.DisplayMax;
641  Opt.DisplayMax = -tmp;
642end
643
644ploth.PlotLine = plot(xd, yd);
645set(gca, ...
646    'XLim', [1 max([2, len])], ...
647    'YLim', sort([Opt.DisplayMin Opt.DisplayMax]));
648if ~Opt.ShowRange
649  set(gca, ...
650      'XTickLabel', '', ...
651      'YTickLabel', '', ...
652      'XTick', [], ...
653      'YTick', []);
654  ploth.MaxLabel = [];
655  ploth.MinLabel = [];
656  ploth.DimLabel = [];
657else
658  % get TickLabels used by MatLab
659  set(gca, ...
660      'YTick', [Opt.DisplayMin Opt.DisplayMax]);
661  labelstr = get(gca, 'YTickLabel');
662  labelstr = {deblank(labelstr(1,:)) deblank(labelstr(2,:))};
663
664  if UpDownPlot
665    for i=1:2
666      if labelstr{i}(1) == '-'
667        labelstr{i} = labelstr{i}(2:length(labelstr{i}));
668      else
669        labelstr{i} = ['-' labelstr{i}];
670      end
671    end
672  end
673
674  set(gca, 'YTickLabel', '');
675  % place TickLabels
676  ploth.MinLabel = text(0, 0, ...
677      labelstr{1}, ...
678      'Parent', gca, ...
679      'HorizontalAlignment', 'right', ...
680      'VerticalAlignment', 'baseline', ...
681      'Units', 'normalized');
682  ploth.MaxLabel = text(0, 1, ...
683      labelstr{2}, ...
684      'Parent', gca, ...
685      'HorizontalAlignment', 'right', ...
686      'VerticalAlignment', 'cap', ...
687      'Units', 'normalized');
688  % place physical dimension
689  ploth.DimLabel = text(0, 0.5, ...
690      ['[' Opt.YLabel ']'], ...
691      'Parent', gca, ...
692      'HorizontalAlignment', 'right', ...
693      'VerticalAlignment', 'middle', ...
694      'Units', 'normalized');
695end
696
697ButWidth = Opt.TextWidth / 3;
698ploth.RecButton = uicontrol(gcf, ...
699    'Style', 'PushButton', ...
700    'Units', 'Normalized', ...
701    'String', '?', ...
702    'Position', [Opt.TextX, Opt.YPos, ButWidth, Opt.ButHeight], ...
703    'Callback', 'viewedf RecordProp', ...
704    'UserData', Opt.UserData);
705ploth.ScaleUpButton = uicontrol(gcf, ...
706    'Style', 'PushButton', ...
707    'Units', 'Normalized', ...
708    'String', '+', ...
709    'Position', [Opt.TextX+ButWidth, Opt.YPos, ButWidth, Opt.ButHeight], ...
710    'Callback', 'viewedf ScaleUp', ...
711    'UserData', Opt.UserData);
712ploth.ScaleDownButton = uicontrol(gcf, ...
713    'Style', 'PushButton', ...
714    'Units', 'Normalized', ...
715    'String', '-', ...
716    'Position', [Opt.TextX+2*ButWidth, Opt.YPos, ButWidth, Opt.ButHeight], ...
717    'Callback', 'viewedf ScaleDown', ...
718    'UserData', Opt.UserData);
719ploth.RecLabel = uicontrol(gcf, ...
720    'Style', 'Text', ...
721    'Units', 'Normalized', ...
722    'String', Opt.Label, ...
723    'Position', [Opt.TextX, Opt.YPos + Opt.FigHeight - Opt.YSpace - ...
724      Opt.TxtHeight, Opt.TextWidth, Opt.TxtHeight]);
725
726
727%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
728% LocalAssignMat
729% Save display to Matrix
730function LocalAssignMat()
731Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
732if length(Data.EDF)==0
733  errordlg('No EDF-File is open!', 'Error');
734  return;
735end
736
737answer = inputdlg({'Target name'}, 'Save to cell-array', 1, {''});
738if (length(answer) == 0)
739  return;
740end
741cnt = 0;
742for j=1:length(Data.EDF)
743  for i=1:length(Data.Display.EDF(j).ShowSignals)
744    cnt = cnt+1;
745    showsig = Data.Display.EDF(j).ShowSignals(i);
746    res{cnt} = Data.EDF(j).Record{showsig};
747  end
748end
749for j=1:length(Data.Plugin)
750  for i=1:length(Data.Display.Plugin(j).ShowSignals)
751    cnt = cnt+1;
752    Data.Plugin(j)
753    showsig = Data.Display.Plugin(j).ShowSignals(i);
754    res{cnt} = Data.Plugin(j).EDF.Record{showsig};
755  end
756end
757assignin('base', answer{1}, res);
758
759%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
760% LocalGetEDFInfo
761% get information of all open EDF files
762function [res] = LocalGetEDFInfo(Which, EDF)
763
764res = [];
765for k=1:length(EDF),
766	switch Which
767	case 'NRec'
768		res = [res,EDF(k).Head.NRec];
769	case 'Dur'
770		res = [res,EDF(k).Head.SPR / EDF(k).Head.SampleRate];
771	case 'SPR'
772		res = [res,EDF(k).Head.SPR];
773	case 'FileDur'
774		res = [res,EDF(k).Head.NRec * EDF(k).Head.SPR / EDF(k).Head.SampleRate];
775	end
776end;
777
778%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
779% LocalAddPlugin
780% Add plugin function
781function LocalAddPlugin()
782Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
783if length(Data.EDF)==0
784  errordlg('No EDF-File is open!', 'Error');
785  return;
786end
787
788res=inputdlg({ 'Enter Plugin name','Label (Optional)', ...
789    'Parameters (Optional)'}, 'Select Plugin', 1, { '', '', ''});
790if isempty(res)
791  return;
792end
793plugname = res{1};
794pluglabel = res{2};
795plugopt = res{3};
796if isempty(pluglabel)
797  pluglabel = plugname;
798end
799if ~exist(plugname, 'file');
800  errordlg(sprintf('Plugin %s can not be found in standard search path', ...
801      upper(plugname)), 'Plugin Error');
802  return
803end;
804
805% select EDF file if several files are open
806infile = 1;
807if (length(Data.EDF) > 1)
808  [infile, cancelled] = LocalSelectEDFFile({'EDF-data passed to plugin', ...
809        'Select'}, Data.EDF);
810  if cancelled
811    return
812  end
813end
814
815% set all variables
816ind = length(Data.Plugin) + 1;
817Data.Plugin(ind).Name = plugname;
818Data.Plugin(ind).Label = pluglabel;
819Data.Plugin(ind).UserData = plugopt;
820Data.Plugin(ind).EDFFile = infile;
821LocalWatchOn;
822[Data.Plugin(ind).EDF, Data.Plugin(ind).UserData] = ...
823    feval(Data.Plugin(ind).Name, Data.EDF(infile), ...
824    Data.Plugin(ind).UserData, 'Reset');
825LocalWatchOff;
826Data.Display.Plugin(ind).ShowSignals = 1:Data.Plugin(ind).EDF.Head.NS;
827Data.Display.Plugin(ind).DisplayMin = Data.Plugin(ind).EDF.Head.PhysMin;
828Data.Display.Plugin(ind).DisplayMax = Data.Plugin(ind).EDF.Head.PhysMax;
829Data.Display.Plugin(ind).StairPlot = ...
830    zeros(1, Data.Plugin(ind).EDF.Head.NS);
831Data.Display.Plugin(ind).UpDownPlot = ...
832    zeros(1, Data.Plugin(ind).EDF.Head.NS);
833MaxDur = max(LocalGetEDFInfo('Dur', Data.EDF));
834Data.Display.Plugin(ind).ShowRecords = [0 ...
835      round(Data.Plugin(ind).EDF.Head.Dur / MaxDur)];
836
837% Add menu entry to options menu
838Data.Display.PluginMenu.Sub(ind) = uimenu(Data.Display.PluginMenu.Main, ...
839    'Label', [pluglabel, ' (File ', upper(plugname), ')'], ...
840    'UserData', ind, ...
841    'Callback', 'viewedf PluginMenu');
842set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
843LocalRepaint(0);
844
845%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
846% LocalRemovePlugin
847% Remove plugin function
848function LocalRemovePlugin(whichplugin)
849Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
850
851if nargin == 0
852  % determine which plugin to remove
853  if length(Data.EDF)==0
854    errordlg('No EDF-File is open!', 'Error');
855    return;
856  end
857  if length(Data.Plugin) == 0
858    errordlg('No Plugins are loaded!', 'Error');
859    return;
860  end
861
862  dlgh = dialog(...
863      'Name', 'Remove Plugin', ...
864      'CloseRequestFcn', 'set(gcf,''UserData'',''Cancel'');uiresume;');
865  dlgpos = get(dlgh, 'Position');
866  set(dlgh, 'Position', [dlgpos(1),dlgpos(2),200,100]);
867
868  PlugNames = {};
869  % get Plugin names
870  for i = 1:length(Data.Plugin)
871    PlugNames = {PlugNames{:}, [Data.Plugin(i).Label, ' (File ', ...
872            upper(Data.Plugin(i).Name), ')']};
873  end
874
875  poph = uicontrol(dlgh, ...
876      'Style', 'Popup', ...
877      'Units', 'Normalized', ...
878      'String', PlugNames, ...
879      'Value', 1, ...
880      'Position', [0.05, 0.5, 0.9, 0.35]);
881  % buttons
882  uicontrol(dlgh, ...
883      'Style', 'PushButton', ...
884      'Units', 'Normalized', ...
885      'String', 'Remove', ...
886      'Position', [0.1, 0.05, 0.3, 0.3], ...
887      'Callback', 'set(gco,''UserData'',''OK'');uiresume;');
888  uicontrol(dlgh, ...
889      'Style', 'PushButton', ...
890      'Units', 'Normalized', ...
891      'String', 'Cancel', ...
892      'Position', [0.6, 0.05, 0.3, 0.3], ...
893      'Callback', 'set(gco,''UserData'',''Cancel'');uiresume;');
894
895  drawnow;
896  uiwait(dlgh);
897  whichplugin = get(poph, 'Value');
898  selbutton = get(gco,'UserData');
899  delete(dlgh);
900  if strcmp(selbutton,'Cancel')
901    return
902  end
903end
904
905delete(Data.Display.PluginMenu.Sub(whichplugin));
906for i = whichplugin:length(Data.Plugin)-1
907  Data.Display.PluginMenu.Sub(i) = Data.Display.PluginMenu.Sub(i+1);
908  set(Data.Display.PluginMenu.Sub(i), 'UserData', i);
909  Data.Display.Plugin(i) = Data.Display.Plugin(i+1);
910  Data.Plugin(i) = Data.Plugin(i+1);
911end
912ind = length(Data.Plugin) - 1;
913if ind == 0
914  Data.Plugin = [];
915  Data.Display.Plugin = [];
916  Data.Display.PluginMenu.Sub = [];
917else
918  Data.Plugin = Data.Plugin(1:ind);
919  Data.Display.Plugin = Data.Display.Plugin(1:ind);
920  Data.Display.PluginMenu.Sub = Data.Display.PluginMenu.Sub(1:ind);
921end
922set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
923LocalRepaint;
924
925%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926% LocalPluginMenu
927% Call plugin for setup
928function LocalPluginMenu()
929ind = get(gcbo, 'UserData');
930Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
931[Data.Plugin(ind).EDF, Data.Plugin(ind).UserData] = ...
932    feval(Data.Plugin(ind).Name, Data.EDF(Data.Plugin(ind).EDFFile), ...
933    Data.Plugin(ind).UserData, 'Menu');
934% Uncomment to reset display properties after a call of the plugin-menu
935%Data.Display.Plugin(ind).ShowSignals = 1:Data.Plugin(ind).EDF.Head.NS;
936%Data.Display.Plugin(ind).DisplayMin = Data.Plugin(ind).EDF.Head.PhysMin;
937%Data.Display.Plugin(ind).DisplayMax = Data.Plugin(ind).EDF.Head.PhysMax;
938%Data.Display.Plugin(ind).StairPlot = ...
939%    zeros(1, Data.Plugin(ind).EDF.Head.NS);
940%Data.Display.Plugin(ind).UpDownPlot = ...
941%    zeros(1, Data.Plugin(ind).EDF.Head.NS);
942set(findobj('Tag', 'ViewEDFFigure'), 'UserData',Data);
943LocalRepaint(0);
944
945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
946% LocalChangeRecord
947% Change displayed page
948function LocalChangeRecord(increment, changetype)
949Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
950if length(Data.EDF) == 0
951  errordlg('No EDF-File is open!', 'Error');
952  return;
953end
954Dur = LocalGetEDFInfo('Dur',Data.EDF);
955[MDur, MDInd] = max(Dur);
956FLen = max(LocalGetEDFInfo('FileDur', Data.EDF));
957[MFLen, MFInd] = max(FLen);
958
959RelInc = round(ones(size(Dur)) * max(Dur) ./ Dur);
960Inc = increment * RelInc;
961
962for i = 1:length(Data.EDF)
963  switch changetype
964    case 0 % incremental
965      Data.Display.EDF(i).ShowRecords(1) = Data.Display.EDF(i).ShowRecords(1) ...
966          + Inc(i) * Data.Display.EDF(MDInd).ShowRecords(2);
967    case 1 % absolute
968      Data.Display.EDF(i).ShowRecords(1) = Inc(i);
969  end
970end
971
972% check whether we are moving to far
973temp = Data.Display.EDF(MDInd).ShowRecords(1);
974if temp < 0
975  for i = 1:length(Data.EDF)
976    Data.Display.EDF(i).ShowRecords(1) = Data.Display.EDF(i).ShowRecords(1) ...
977        - temp * RelInc(i);
978  end
979end
980
981temp = sum(Data.Display.EDF(MFInd).ShowRecords(1:2)) - ...
982    Data.EDF(MFInd).Head.NRec;
983if temp > 0
984  temp = ceil(temp / RelInc(MFInd));
985  for i = 1:length(Data.EDF)
986    Data.Display.EDF(i).ShowRecords(1) = Data.Display.EDF(i).ShowRecords(1) - ...
987        temp * RelInc(i);
988  end
989end
990
991for i=1:length(Data.EDF)
992  temp = sum(Data.Display.EDF(i).ShowRecords(1:2)) - ...
993      Data.EDF(i).Head.NRec;
994  whichrec(1) = Data.Display.EDF(i).ShowRecords(1);
995  if temp > 0
996    % do not read to much data
997    whichrec(2) = Data.Display.EDF(i).ShowRecords(2) - temp;
998    if (whichrec(2) < 0)
999      whichrec(2) = 0;
1000    end
1001    [temp, Data.EDF(i).Head] = LocalEDFRead(Data.EDF(i).Head, whichrec);
1002    for j = 1:Data.EDF(i).Head.NS
1003      Data.EDF(i).Record{j} = zeros(Data.Display.EDF(i).ShowRecords(2) * ...
1004          Data.EDF(i).Head.SPR(j));
1005      if ~isempty(temp)
1006        Data.EDF(i).Record{j}(1:length(temp{j})) = temp{j};
1007      end
1008    end
1009
1010  else
1011    [Data.EDF(i).Record, Data.EDF(i).Head] = ...
1012        LocalEDFRead(Data.EDF(i).Head, Data.Display.EDF(i).ShowRecords);
1013  end
1014end
1015set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1016LocalRepaint(1);
1017
1018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1019% LocalHSroll
1020% Goto record
1021function LocalHScroll
1022Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1023MaxVal = max(LocalGetEDFInfo('FileDur',Data.EDF));
1024MaxDur = max(LocalGetEDFInfo('Dur', Data.EDF));
1025pos = get(gcbo, 'Value');
1026LocalChangeRecord(round(pos*MaxVal/MaxDur), 1);
1027
1028%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1029% LocalGotoRecord
1030% Goto record
1031function LocalGotoRecord(Pos)
1032Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1033if length(Data.EDF)==0
1034  errordlg('No EDF-File is open!', 'Error');
1035  return;
1036end
1037
1038[temp, ind] = max(LocalGetEDFInfo('Dur', Data.EDF));
1039
1040if (nargin == 0)
1041  answer = inputdlg({'Select record'}, 'Change start record', 1, ...
1042                    {int2str(Data.Display.EDF(ind).ShowRecords(1))});
1043  if (length(answer) ~= 0)
1044    answer = str2num(answer{1});
1045    if ~isempty(answer)
1046      LocalChangeRecord(answer, 1);
1047    end
1048  end
1049else
1050  Pos = round(Pos);
1051  if Pos >= 0
1052    LocalChangeRecord(Pos, 1);
1053  end
1054end
1055
1056
1057%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1058% LocalGotoSecond
1059% Goto second
1060function LocalGotoSecond(Pos)
1061Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1062if length(Data.EDF)==0
1063  errordlg('No EDF-File is open!', 'Error');
1064  return;
1065end
1066
1067[temp, ind] = max(LocalGetEDFInfo('Dur', Data.EDF));
1068
1069if (nargin == 0)
1070  answer = inputdlg({'Select second'}, 'Change start time', 1, ...
1071    {int2str(round(Data.Display.EDF(ind).ShowRecords(1) / ...
1072      Data.EDF(ind).Head.Dur))});
1073  if (length(answer) ~= 0)
1074    answer = str2num(answer{1});
1075    if ~isempty(answer)
1076      LocalChangeRecord(answer / Data.EDF(ind).Head.Dur, 1);
1077    end
1078  end
1079else
1080  Pos = round(Pos / Data.EDF(ind).Head.Dur);
1081  if Pos >= 0
1082    LocalChangeRecord(Pos, 1);
1083  end
1084end
1085
1086
1087%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1088% LocalRecordProp
1089% display channel properties
1090function LocalRecordProp()
1091Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1092if length(Data.EDF)==0
1093  errordlg('No EDF-File is open!', 'Error');
1094  return;
1095end
1096
1097whichbut = get(gcbo, 'UserData');
1098Rec = whichbut{2};
1099Num = whichbut{3};
1100switch whichbut{1}
1101  case 'EDF'
1102    RecHead = Data.EDF(Num).Head;
1103    RecDisp = Data.Display.EDF(Num);
1104    DataType = 'EDF File';
1105    TypeString = 'Filename :';
1106    OptString = [Data.EDF(Num).Head.FILE.Name '.' Data.EDF(Num).Head.FILE.Ext];
1107  case 'PLUGIN'
1108    RecHead = Data.Plugin(Num).EDF.Head;
1109    RecDisp = Data.Display.Plugin(Num);
1110    DataType = 'Plugin';
1111    TypeString = 'Name :';
1112    OptString = Data.Plugin(Num).Label;
1113end
1114dlgh = dialog(...
1115    'Name', 'Channel Information', ...
1116    'CloseRequestFcn', 'set(gcf,''UserData'',''Cancel'');uiresume;');
1117dlgpos = get(dlgh, 'Position');
1118set(dlgh, 'Position', [dlgpos(1),dlgpos(2),350,300]);
1119Fnthgt = LocalGetFontHeight;
1120yinc = 0.085;
1121% general information
1122linenum=1;
1123uicontrol(dlgh, ...
1124    'Style', 'Text', ...
1125    'Units', 'Normalized', ...
1126    'HorizontalAlignment', 'left', ...
1127    'FontWeight', 'bold', ...
1128    'String', [ 'Record read from ' DataType], ...
1129    'Position', [0.02, 1-linenum*yinc, 0.96, Fnthgt ]);
1130% filename
1131linenum=linenum+1;
1132uicontrol(dlgh, ...
1133    'Style', 'Text', ...
1134    'Units', 'Normalized', ...
1135    'HorizontalAlignment', 'left', ...
1136    'String', TypeString, ...
1137    'Position', [0.02, 1-linenum*yinc, 0.96, Fnthgt]);
1138uicontrol(dlgh, ...
1139    'Style', 'Text', ...
1140    'Units', 'Normalized', ...
1141    'HorizontalAlignment', 'left', ...
1142    'FontWeight', 'bold', ...
1143    'String', OptString, ...
1144    'Position', [0.35, 1-linenum*yinc, 0.63, Fnthgt]);
1145% label
1146linenum=linenum+1;
1147uicontrol(dlgh, ...
1148    'Style', 'Text', ...
1149    'Units', 'Normalized', ...
1150    'HorizontalAlignment', 'left', ...
1151    'String', 'Label : ', ...
1152    'Position', [0.02, 1-linenum*yinc, 0.96, Fnthgt]);
1153uicontrol(dlgh, ...
1154    'Style', 'Text', ...
1155    'Units', 'Normalized', ...
1156    'HorizontalAlignment', 'left', ...
1157    'FontWeight', 'bold', ...
1158    'String', RecHead.Label(Rec,:), ...
1159    'Position', [0.35, 1-linenum*yinc, 0.63, Fnthgt]);
1160% Transducer
1161linenum=linenum+1;
1162uicontrol(dlgh, ...
1163  'Style', 'Text', ...
1164  'Units', 'Normalized', ...
1165  'HorizontalAlignment', 'left', ...
1166  'String', 'Transducer :', ...
1167  'Position', [0.02, 1-linenum*yinc, 0.96, Fnthgt]);
1168uicontrol(dlgh, ...
1169    'Style', 'Text', ...
1170    'Units', 'Normalized', ...
1171    'HorizontalAlignment', 'left', ...
1172    'FontWeight', 'bold', ...
1173    'String', RecHead.Transducer(Rec, :), ...
1174    'Position', [0.35, 1-linenum*yinc, 0.63, Fnthgt]);
1175% Prefilter
1176linenum=linenum+1;
1177uicontrol(dlgh, ...
1178    'Style', 'Text', ...
1179    'Units', 'Normalized', ...
1180    'HorizontalAlignment', 'left', ...
1181    'String', 'Prefilter :', ...
1182    'Position', [0.02, 1-linenum*yinc, 0.96, Fnthgt]);
1183uicontrol(dlgh, ...
1184    'Style', 'Text', ...
1185    'Units', 'Normalized', ...
1186    'HorizontalAlignment', 'left', ...
1187    'FontWeight', 'bold', ...
1188    'String', RecHead.PreFilt(Rec, :), ...
1189    'Position', [0.35, 1-linenum*yinc, 0.63, Fnthgt]);
1190% samples per records
1191linenum=linenum+1;
1192uicontrol(dlgh, ...
1193    'Style', 'Text', ...
1194    'Units', 'Normalized', ...
1195    'HorizontalAlignment', 'left', ...
1196    'String', 'Samples per record  :', ...
1197    'Position', [0.02, 1-linenum*yinc, 0.96, Fnthgt]);
1198uicontrol(dlgh, ...
1199    'Style', 'Text', ...
1200    'Units', 'Normalized', ...
1201    'HorizontalAlignment', 'left', ...
1202    'FontWeight', 'bold', ...
1203    'String', sprintf('%d', RecHead.SPR), ...
1204    'Position', [0.35, 1-linenum*yinc, 0.63, Fnthgt]);
1205% physical min
1206linenum=linenum+1;
1207uicontrol(dlgh, ...
1208    'Style', 'Text', ...
1209    'Units', 'Normalized', ...
1210    'HorizontalAlignment', 'left', ...
1211    'String', 'Physical min :', ...
1212    'Position', [0.02, 1-linenum*yinc, 0.45, Fnthgt]);
1213uicontrol(dlgh, ...
1214    'Style', 'Text', ...
1215    'Units', 'Normalized', ...
1216    'HorizontalAlignment', 'left', ...
1217    'FontWeight', 'bold', ...
1218    'String', sprintf('%f', RecHead.PhysMin(Rec)), ...
1219    'Position', [0.25, 1-linenum*yinc, 0.25, Fnthgt]);
1220% physical max
1221uicontrol(dlgh, ...
1222    'Style', 'Text', ...
1223    'Units', 'Normalized', ...
1224    'HorizontalAlignment', 'left', ...
1225    'String', 'Physical max :', ...
1226    'Position', [0.52, 1-linenum*yinc, 0.45, Fnthgt]);
1227uicontrol(dlgh, ...
1228    'Style', 'Text', ...
1229    'Units', 'Normalized', ...
1230    'HorizontalAlignment', 'left', ...
1231    'FontWeight', 'bold', ...
1232    'String', sprintf('%f', RecHead.PhysMax(Rec)), ...
1233    'Position', [0.77, 1-linenum*yinc, 0.25, Fnthgt]);
1234% digital min
1235linenum=linenum+1;
1236uicontrol(dlgh, ...
1237    'Style', 'Text', ...
1238    'Units', 'Normalized', ...
1239    'HorizontalAlignment', 'left', ...
1240    'String', 'Digital min :', ...
1241    'Position', [0.02, 1-linenum*yinc, 0.45, Fnthgt]);
1242uicontrol(dlgh, ...
1243    'Style', 'Text', ...
1244    'Units', 'Normalized', ...
1245    'HorizontalAlignment', 'left', ...
1246    'FontWeight', 'bold', ...
1247    'String', sprintf('%d', RecHead.DigMin(Rec)), ...
1248    'Position', [0.25, 1-linenum*yinc, 0.25, Fnthgt]);
1249% digital max
1250uicontrol(dlgh, ...
1251    'Style', 'Text', ...
1252    'Units', 'Normalized', ...
1253    'HorizontalAlignment', 'left', ...
1254    'String', 'Digital max :', ...
1255    'Position', [0.52, 1-linenum*yinc, 0.45, Fnthgt]);
1256uicontrol(dlgh, ...
1257    'Style', 'Text', ...
1258    'Units', 'Normalized', ...
1259    'HorizontalAlignment', 'left', ...
1260    'FontWeight', 'bold', ...
1261    'String', sprintf('%d', RecHead.DigMax(Rec)), ...
1262    'Position', [0.77, 1-linenum*yinc, 0.25, Fnthgt]);
1263% display min
1264linenum=linenum+1;
1265uicontrol(dlgh, ...
1266    'Style', 'Text', ...
1267    'Units', 'Normalized', ...
1268    'HorizontalAlignment', 'left', ...
1269    'String', 'Display min :', ...
1270    'Position', [0.02, 1-linenum*yinc, 0.2, Fnthgt]);
1271dminh = uicontrol(dlgh, ...
1272    'Style', 'Edit', ...
1273    'Units', 'Normalized', ...
1274    'HorizontalAlignment', 'left', ...
1275    'BackGroundColor', [1 1 1], ...
1276    'String', sprintf('%f', RecDisp.DisplayMin(Rec)), ...
1277    'Position', [0.25, 1-linenum*yinc, 0.20, Fnthgt+0.02]);
1278LocalResizeUI(dminh, [NaN 1.1 0 0]);
1279% display max
1280uicontrol(dlgh, ...
1281    'Style', 'Text', ...
1282    'Units', 'Normalized', ...
1283    'HorizontalAlignment', 'left', ...
1284    'String', 'Display max :', ...
1285    'Position', [0.52, 1-linenum*yinc, 0.2, Fnthgt]);
1286dmaxh = uicontrol(dlgh, ...
1287    'Style', 'Edit', ...
1288    'Units', 'Normalized', ...
1289    'HorizontalAlignment', 'left', ...
1290    'BackGroundColor', [1 1 1], ...
1291    'String', sprintf('%f', RecDisp.DisplayMax(Rec)), ...
1292    'Position', [0.77, 1-linenum*yinc, 0.20, Fnthgt+0.02]);
1293LocalResizeUI(dmaxh, [NaN 1.1 0 0]);
1294% Plot-type
1295linenum=linenum+1;
1296ploth = uicontrol(dlgh, ...
1297    'Style', 'CheckBox', ...
1298    'Units', 'Normalized', ...
1299    'String', '  Stairstep-Plot', ...
1300    'Value', RecDisp.StairPlot(Rec), ...
1301    'Position', [0.02, 1-linenum*yinc, 0.7, Fnthgt]);
1302LocalResizeUI(ploth, [1 1 0.05 0]);
1303% Invert plot
1304updownh = uicontrol(dlgh, ...
1305    'Style', 'CheckBox', ...
1306    'Units', 'Normalized', ...
1307    'String', '  Plot upside down', ...
1308    'Value', RecDisp.UpDownPlot(Rec), ...
1309    'Position', [0.52, 1-linenum*yinc, 0.7, Fnthgt]);
1310LocalResizeUI(updownh, [1 1 0.05 0]);
1311% buttons
1312linenum=linenum+1;
1313uicontrol(dlgh, ...
1314    'Style', 'PushButton', ...
1315    'Units', 'Normalized', ...
1316    'String', 'OK', ...
1317    'Position', [0.05, 0.02, 0.3, 0.08], ...
1318    'Callback', 'set(gco,''UserData'',''OK'');uiresume;');
1319uicontrol(dlgh, ...
1320    'Style', 'PushButton', ...
1321    'Units', 'Normalized', ...
1322    'String', 'Apply to all', ...
1323    'Position', [0.4, 0.02, 0.2, 0.08], ...
1324    'Callback', 'set(gco,''UserData'',''ApplyAll'');uiresume;');
1325uicontrol(dlgh, ...
1326    'Style', 'PushButton', ...
1327    'Units', 'Normalized', ...
1328    'String', 'Cancel', ...
1329    'Position', [0.65, 0.02, 0.3, 0.08], ...
1330    'Callback', 'set(gco,''UserData'',''Cancel'');uiresume;');
1331
1332drawnow;
1333uiwait(dlgh);
1334changed = 0;
1335if ~strcmp(get(gco,'UserData'),'Cancel')
1336  dmin = str2num(get(dminh, 'String'));
1337  dmax = str2num(get(dmaxh, 'String'));
1338  stplot = get(ploth, 'Value');
1339  udplot = get(updownh, 'Value');
1340  if (length(dmin) == 1) && (length(dmax) == 1) && (dmin < dmax),
1341    changed = 1;
1342    if strcmp(get(gco,'UserData'),'OK')
1343      switch(whichbut{1})
1344       case 'EDF'
1345        Data.Display.EDF(Num).DisplayMin(Rec) = dmin;
1346        Data.Display.EDF(Num).DisplayMax(Rec) = dmax;
1347        Data.Display.EDF(Num).StairPlot(Rec) = stplot;
1348        Data.Display.EDF(Num).UpDownPlot(Rec) = udplot;
1349       case 'PLUGIN'
1350        Data.Display.Plugin(Num).DisplayMin(Rec) = dmin;
1351        Data.Display.Plugin(Num).DisplayMax(Rec) = dmax;
1352        Data.Display.Plugin(Num).StairPlot(Rec) = stplot;
1353        Data.Display.Plugin(Num).UpDownPlot(Rec) = udplot;
1354      end
1355    else
1356      % set all files
1357      for fnum = 1:length(Data.Display.EDF)
1358        for rec = 1:length(Data.Display.EDF(fnum).DisplayMin)
1359          Data.Display.EDF(fnum).DisplayMin(rec) = dmin;
1360          Data.Display.EDF(fnum).DisplayMax(rec) = dmax;
1361          Data.Display.EDF(fnum).StairPlot(rec) = stplot;
1362          Data.Display.EDF(fnum).UpDownPlot(rec) = udplot;
1363        end
1364      end
1365      if isfield(Data.Display, 'Plugin')
1366        for fnum = 1:length(Data.Display.Plugin)
1367          for rec = 1:length(Data.Display.Plugin(fnum).DisplayMin)
1368            Data.Display.Plugin(fnum).DisplayMin(rec) = dmin;
1369            Data.Display.Plugin(fnum).DisplayMax(rec) = dmax;
1370            Data.Display.Plugin(fnum).StairPlot(rec) = stplot;
1371            Data.Display.Plugin(fnum).UpDownPlot(rec) = udplot;
1372          end
1373        end
1374      end
1375    end
1376  end
1377end
1378delete(dlgh);
1379if changed
1380  set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1381  LocalRepaint;
1382end
1383
1384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1385% LocalRescale
1386% change range of a plot
1387function LocalRescale(Mode)
1388Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1389whichbut = get(gcbo, 'UserData');
1390Rec = whichbut{2};
1391Num = whichbut{3};
1392
1393switch(whichbut{1})
1394  case 'EDF'
1395    DisData = Data.Display.EDF(Num);
1396    [DisData.DisplayMin(Rec), DisData.DisplayMax(Rec)] = ...
1397        LocalCalcNewRange(DisData.DisplayMin(Rec), DisData.DisplayMax(Rec), ...
1398        Mode);
1399    Data.Display.EDF(Num) = DisData;
1400  case 'PLUGIN'
1401    DisData = Data.Display.Plugin(Num);
1402    [DisData.DisplayMin(Rec), DisData.DisplayMax(Rec)] = ...
1403        LocalCalcNewRange(DisData.DisplayMin(Rec), DisData.DisplayMax(Rec), ...
1404        Mode);
1405    Data.Display.Plugin(Num) = DisData;
1406end
1407set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1408LocalRepaint;
1409
1410%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1411% LocalRescaleAll
1412% change range of all plots
1413function LocalRescaleAll(Mode)
1414Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1415if length(Data.EDF)==0
1416  return;
1417end
1418% EDF files
1419for i=1:length(Data.EDF)
1420  DisData = Data.Display.EDF(i);
1421  [DisData.DisplayMin, DisData.DisplayMax] = ...
1422      LocalCalcNewRange(DisData.DisplayMin, DisData.DisplayMax, Mode);
1423  Data.Display.EDF(i) = DisData;
1424end
1425% plugins
1426for i=1:length(Data.Plugin)
1427  DisData = Data.Display.Plugin(i);
1428  [DisData.DisplayMin, DisData.DisplayMax] = ...
1429      LocalCalcNewRange(DisData.DisplayMin, DisData.DisplayMax, Mode);
1430  Data.Display.Plugin(i) = DisData;
1431end
1432set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1433LocalRepaint;
1434
1435%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436% LocalCalcNewRange
1437% calculate new range for plots
1438function [ResMin, ResMax] = LocalCalcNewRange(PMin, PMax, Mode)
1439dmean = (PMin+PMax) / 2;
1440switch Mode
1441  case 'up'
1442    ResMin = (PMin - dmean)*0.5 + dmean;
1443    ResMax = (PMax - dmean)*0.5 + dmean;
1444  case 'down'
1445    ResMin = (PMin - dmean)*2 + dmean;
1446    ResMax = (PMax - dmean)*2 + dmean;
1447  otherwise
1448    ResMin = PMin;
1449    ResMax = PMax;
1450end
1451
1452
1453%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1454% LocalToggleUpdatePlugin
1455% Toggle flag for updating plugin-results
1456function LocalToggleUpdatePlugin()
1457Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1458Data.UpdatePlugin = ~Data.UpdatePlugin;
1459if Data.UpdatePlugin
1460  set(gcbo, 'Checked', 'on');
1461else
1462  set(gcbo, 'Checked', 'off');
1463end
1464set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1465
1466%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1467% LocalToggleShowRange
1468% Toggle flag for showing plot ranges
1469function LocalToggleShowRange()
1470Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1471Data.ShowRange = ~Data.ShowRange;
1472if Data.ShowRange
1473  set(gcbo, 'Checked', 'on');
1474else
1475  set(gcbo, 'Checked', 'off');
1476end
1477set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1478LocalRepaint;
1479
1480%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1481% LocalToggleShowCursor
1482% Toggle flag for showing cursor
1483function LocalToggleShowCursor()
1484figure(findobj('Tag', 'ViewEDFFigure'));
1485Data = get(gcf, 'UserData');
1486Data.ShowCursor = ~Data.ShowCursor;
1487if Data.ShowCursor
1488  set(gcbo, 'Checked', 'on');
1489  set(gcf, 'WindowButtonDownFcn', 'viewedf MoveCursor Down');
1490  Data.Display.Cursor = LocalDrawCursor(Data.Display);
1491else
1492  delete(Data.Display.Cursor.Line(:));
1493  delete(Data.Display.Cursor.Menu.Text);
1494  delete(Data.Display.Cursor.Menu.Menu);
1495  Data.Display.Cursor = [];
1496  set(gcbo, 'Checked', 'off');
1497  set(gcf, 'WindowButtonMotionFcn', '', ...
1498           'WindowButtonDownFcn', '', ...
1499           'WindowButtonUpFcn', '');
1500end
1501set(gcf, 'UserData', Data);
1502
1503%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1504% LocalDrawCursor
1505% Show cursor
1506function Cursor = LocalDrawCursor(DisplayData, NewPos, TimeStr)
1507if nargin ~= 3
1508  % find good placement for lines
1509  Cursor.Pos = 0.5;
1510  Cursor.Menu.Menu = uicontextmenu;
1511  Cursor.Menu.Text  = uimenu(Cursor.Menu.Menu, ...
1512                             'Label', '', ...
1513                             'Callback', '');
1514  % generate lines
1515  for i=1:length(DisplayData.Axes)
1516    Cursor.AxesLim(i, :) = get(DisplayData.Axes(i).Plot, 'XLim');
1517    XPos = Cursor.AxesLim(i,1) + (Cursor.AxesLim(i,2) - Cursor.AxesLim(i,1)) ...
1518           * Cursor.Pos;
1519    Cursor.Line(i) = line('Parent', DisplayData.Axes(i).Plot, ...
1520                          'XData', [XPos XPos], ...
1521                          'YData', get(DisplayData.Axes(i).Plot, 'YLim'), ...
1522                          'EraseMode', 'xor', ...
1523                          'UIContextMenu', Cursor.Menu.Menu, ...
1524                          'Color', [1 0.2 0.2]);
1525    Cursor.AxesPos(i, :) = get(DisplayData.Axes(i).Plot, 'Position');
1526  end
1527else
1528  Cursor = DisplayData.Cursor;
1529  Cursor.Pos = NewPos;
1530  for i=1:length(DisplayData.Axes)
1531    XPos = Cursor.AxesLim(i,1) + (Cursor.AxesLim(i,2) - Cursor.AxesLim(i,1)) ...
1532           * Cursor.Pos;
1533    set(Cursor.Line(i), 'XData', [XPos XPos]);
1534  end
1535  set(Cursor.Menu.Text, 'Label', TimeStr);
1536end
1537
1538%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1539% LocalMoveCursor
1540% Move cursor
1541function LocalMoveCursor(Option)
1542Data = get(gcf, 'UserData');
1543CurrPt = get(gcf, 'CurrentPoint');
1544% check if click was in axis
1545AxPos = Data.Display.Cursor.AxesPos;
1546temp = CurrPt(1) > AxPos(:,1) & CurrPt(1) < (AxPos(:,1) + AxPos(:,3)) & ...
1547       CurrPt(2) > AxPos(:,2) & CurrPt(2) < (AxPos(:,2) + AxPos(:,4));
1548if ~any(temp)
1549  return;
1550end
1551
1552% find axis under pointer and calculate position
1553ax = find(temp);
1554Pos = get(Data.Display.Axes(ax).Plot, 'CurrentPoint');
1555Pos = Pos(2,1);
1556Pos = (Pos - Data.Display.Cursor.AxesLim(ax,1)) / (Data.Display.Cursor.AxesLim(ax,2) ...
1557                                                  - Data.Display.Cursor.AxesLim(ax,1));
1558
1559tsec = Data.EDF(1).Head.Dur * Data.Display.EDF(1).ShowRecords(1) + ...
1560       Data.EDF(1).Head.Dur * Data.Display.EDF(1).ShowRecords(2) * Pos;
1561tmin = floor(tsec/60);
1562tsec = rem(tsec,60);
1563th = floor(tmin/60);
1564tmin = rem(tmin, 60);
1565TimeStr = sprintf('%02d:%02d:%02.1f', th,tmin,tsec);
1566
1567switch Option
1568 case 'Down'
1569  Data.Display.Cursor = LocalDrawCursor(Data.Display, Pos, TimeStr);
1570  set(gcf, 'WindowButtonMotionFcn', 'viewedf MoveCursor Move', ...
1571           'WindowButtonUpFcn', 'viewedf MoveCursor Up');
1572 case 'Move'
1573  Data.Display.Cursor = LocalDrawCursor(Data.Display, Pos, TimeStr);
1574 case 'Up'
1575  set(gcf, 'WindowButtonMotionFcn', '');
1576end
1577set(gcf, 'UserData', Data);
1578
1579%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1580% LocalResizeUI
1581% resize UI control according to label size
1582function uihandle = LocalResizeUI(uihandle, options)
1583if nargin < 2
1584  options = [1 1 0 0];
1585end
1586ext = get(uihandle, 'Extent');
1587pos = get(uihandle, 'Position');
1588if ~isnan(options(1))
1589  pos(3) = ext(3)*options(1) + options(3);
1590end
1591if ~isnan(options(2))
1592  pos(4) = ext(4)*options(2) + options(4);
1593end
1594set(uihandle, 'Position', pos);
1595
1596%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1597% LocalNumRecords
1598% select the number of records to be shown simultaniously
1599function LocalNumRecords()
1600Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1601if length(Data.EDF) == 0
1602  errordlg('No EDF-File is open!', 'Error');
1603  return;
1604end
1605
1606Dur = LocalGetEDFInfo('Dur', Data.EDF);
1607[MaxDur, MDInd] = max(Dur);
1608
1609answer = inputdlg({'Select number of records'}, ...
1610    'Number of records on screen', 1, ...
1611    {int2str(Data.Display.EDF(MDInd).ShowRecords(2))});
1612if (length(answer) ~= 0)
1613  answer = str2num(answer{1});
1614  if ~isempty(answer)
1615    for i=1:length(Data.EDF)
1616      Data.Display.EDF(i).ShowRecords(2) = answer * MaxDur / Dur(i);
1617      [Data.EDF(i).Record, Data.EDF(i).Head] = ...
1618          LocalEDFRead(Data.EDF(i).Head, Data.Display.EDF(i).ShowRecords);
1619    end
1620    set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1621    LocalRepaint(0);
1622  end
1623end
1624
1625%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1626% LocalFileInfo
1627% display information about current file
1628function LocalFileInfo(Update)
1629if nargin == 0
1630  Data=get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1631  if length(Data.EDF)==0
1632    errordlg('No EDF-File is open!', 'Error');
1633    return;
1634  end
1635  dlgh = dialog(...
1636      'Name', 'EDF-File information', ...
1637      'CloseRequestFcn', 'set(gcf,''UserData'',''Cancel'');uiresume;');
1638  dlgpos = get(dlgh, 'Position');
1639  set(dlgh, 'Position', [dlgpos(1),dlgpos(2),450,250]);
1640  fnthght = LocalGetFontHeight;
1641
1642  Local.EDFNames = {};
1643  % get filenames
1644  for i = 1:length(Data.EDF)
1645    Local.EDFNames = {Local.EDFNames{:}, Data.EDF(i).Head.FileName};
1646    Local.EDFInfo{i,1} = Data.EDF(i).Head.VERSION;
1647    Local.EDFInfo{i,2} = Data.EDF(i).Head.PID;
1648    Local.EDFInfo{i,3} = Data.EDF(i).Head.RID;
1649    Local.EDFInfo{i,4} = sprintf('%02d/%02d/%02d', Data.EDF(i).Head.T0([3 2 1]));
1650    Local.EDFInfo{i,5} = sprintf('%02d:%02d:%02d', Data.EDF(i).Head.T0([4 5 6]));
1651    Local.EDFInfo{i,6} = sprintf('%d', Data.EDF(i).Head.NS);
1652    Local.EDFInfo{i,7} = sprintf('%d', Data.EDF(i).Head.NRec);
1653  end
1654
1655  Local.poph = uicontrol(dlgh, ...
1656      'Style', 'Popup', ...
1657      'Units', 'Normalized', ...
1658      'String', Local.EDFNames, ...
1659      'Value', 1, ...
1660      'Position', [0.05, 0.9, 0.9, 0.1], ...
1661      'Callback', 'viewedf FileInfo Update');
1662  LocalResizeUI(Local.poph, [NaN 1.1 0 0]);
1663  %HeaderVersion
1664  num = 1;
1665  yinc = (1 - 4*fnthght) / 8;
1666  ystart = 0.9;
1667  uicontrol(dlgh, ...
1668      'Style', 'Text', ...
1669      'HorizontalAlignment', 'left', ...
1670      'Units', 'Normalized', ...
1671      'String', 'HeaderVersion : ', ...
1672      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1673  Local.txth(num) = uicontrol(dlgh, ...
1674      'Style', 'Text', ...
1675      'HorizontalAlignment', 'left', ...
1676      'Units', 'Normalized', ...
1677      'FontWeight', 'bold', ...
1678      'String', '', ...
1679      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1680  %Patient ID
1681  num = num + 1;
1682  uicontrol(dlgh, ...
1683      'Style', 'Text', ...
1684      'HorizontalAlignment', 'left', ...
1685      'Units', 'Normalized', ...
1686      'String', 'Patient ID : ', ...
1687      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1688  Local.txth(num) = uicontrol(dlgh, ...
1689      'Style', 'Text', ...
1690      'HorizontalAlignment', 'left', ...
1691      'Units', 'Normalized', ...
1692      'FontWeight', 'bold', ...
1693      'String', '', ...
1694      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1695  %Recording ID
1696  num = num + 1;
1697  uicontrol(dlgh, ...
1698      'Style', 'Text', ...
1699      'HorizontalAlignment', 'left', ...
1700      'Units', 'Normalized', ...
1701      'String', 'Recording ID : ', ...
1702      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1703  Local.txth(num) = uicontrol(dlgh, ...
1704      'Style', 'Text', ...
1705      'HorizontalAlignment', 'left', ...
1706      'Units', 'Normalized', ...
1707      'FontWeight', 'bold', ...
1708      'String', '', ...
1709      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1710  % startdate
1711  num = num + 1;
1712  uicontrol(dlgh, ...
1713      'Style', 'Text', ...
1714      'HorizontalAlignment', 'left', ...
1715      'Units', 'Normalized', ...
1716      'String', 'Start date : ', ...
1717      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1718  Local.txth(num) = uicontrol(dlgh, ...
1719      'Style', 'Text', ...
1720      'HorizontalAlignment', 'left', ...
1721      'Units', 'Normalized', ...
1722      'FontWeight', 'bold', ...
1723      'String', '', ...
1724      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1725  % start time
1726  num = num + 1;
1727  uicontrol(dlgh, ...
1728      'Style', 'Text', ...
1729      'HorizontalAlignment', 'left', ...
1730      'Units', 'Normalized', ...
1731      'String', 'Start time : ', ...
1732      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1733  Local.txth(num) = uicontrol(dlgh, ...
1734      'Style', 'Text', ...
1735      'HorizontalAlignment', 'left', ...
1736      'Units', 'Normalized', ...
1737      'FontWeight', 'bold', ...
1738      'String', '', ...
1739      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1740  % Num channels
1741  num = num + 1;
1742  uicontrol(dlgh, ...
1743      'Style', 'Text', ...
1744      'HorizontalAlignment', 'left', ...
1745      'Units', 'Normalized', ...
1746      'String', 'Number of channels : ', ...
1747      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1748  Local.txth(num) = uicontrol(dlgh, ...
1749      'Style', 'Text', ...
1750      'HorizontalAlignment', 'left', ...
1751      'Units', 'Normalized', ...
1752      'FontWeight', 'bold', ...
1753      'String', '', ...
1754      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1755  % num records
1756  num = num + 1;
1757  uicontrol(dlgh, ...
1758      'Style', 'Text', ...
1759      'HorizontalAlignment', 'left', ...
1760      'Units', 'Normalized', ...
1761      'String', 'Number of records : ', ...
1762      'Position', [0.05, ystart - num*yinc, 0.3, fnthght]);
1763  Local.txth(num) = uicontrol(dlgh, ...
1764      'Style', 'Text', ...
1765      'HorizontalAlignment', 'left', ...
1766      'Units', 'Normalized', ...
1767      'FontWeight', 'bold', ...
1768      'String', '', ...
1769      'Position', [0.45, ystart - num*yinc, 0.5, fnthght]);
1770  % buttons
1771  uicontrol(dlgh, ...
1772      'Style', 'PushButton', ...
1773      'Units', 'Normalized', ...
1774      'String', 'OK', ...
1775      'Position', [0.3, 0.02, 0.4, 0.1], ...
1776      'Callback', 'uiresume;');
1777  Data=[];
1778  set(dlgh, 'UserData', Local);
1779  LocalFileInfo('Update');
1780
1781  drawnow;
1782  uiwait(dlgh);
1783  delete(dlgh);
1784else
1785  Data=get(gcf,'UserData');
1786  which = get(Data.poph, 'Value');
1787  for i = 1:7
1788    set(Data.txth(i), 'String', Data.EDFInfo{which,i});
1789  end
1790end
1791
1792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1793% LocalSelectChannels
1794% select channels to be displayed on the screen
1795function LocalSelectChannels(Parameter)
1796if nargin == 0
1797  Data=get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
1798  if length(Data.EDF)==0
1799    errordlg('No EDF-File is open!', 'Error');
1800    return;
1801  end
1802  dlgh = dialog(...
1803      'Name', 'EDF-File information', ...
1804      'CloseRequestFcn', 'uiresume;');
1805
1806  Local.Names = {};
1807  Local.Selected = {};
1808  Local.Label = {};
1809  % get filenames
1810  for i = 1:length(Data.EDF)
1811    Local.Names = {Local.Names{:}, ['EDF: ', Data.EDF(i).Head.FileName]};
1812    temp = zeros(Data.EDF(i).Head.NS,1);
1813    temp(Data.Display.EDF(i).ShowSignals) = 1;
1814    Local.Selected = {Local.Selected{:}, temp};
1815    Local.Label = {Local.Label{:}, Data.EDF(i).Head.Label};
1816  end
1817  %get plugin names
1818  for i = 1:length(Data.Plugin)
1819    Local.Names = {Local.Names{:}, ['Plugin: ', Data.Plugin(i).Label, ...
1820            ' (File ', upper(Data.Plugin(i).Name), ')']};
1821    temp = zeros(Data.Plugin(i).EDF.Head.NS,1);
1822    temp(Data.Display.Plugin(i).ShowSignals) = 1;
1823    Local.Selected = {Local.Selected{:}, temp};
1824    Local.Label = {Local.Label{:}, Data.Plugin(i).EDF.Head.Label};
1825  end
1826
1827  uicontrol(dlgh, ...
1828      'Style', 'Frame', ...
1829      'Units', 'Normalized', ...
1830      'Position', [0.02, 0.12, 0.96, 0.76]);
1831  Local.Poph = uicontrol(dlgh, ...
1832      'Style', 'Popup', ...
1833      'Units', 'Normalized', ...
1834      'String', Local.Names, ...
1835      'Value', 1, ...
1836      'Position', [0.05, 0.9, 0.9, 0.1], ...
1837      'Callback', 'viewedf Channels Update');
1838  LocalResizeUI(Local.Poph, [NaN 1.1 0 0]);
1839  % buttons
1840  uicontrol(dlgh, ...
1841      'Style', 'PushButton', ...
1842      'Units', 'Normalized', ...
1843      'String', 'Select', ...
1844      'Position', [0.1, 0.14, 0.3, 0.08], ...
1845      'Callback', 'viewedf Channels Select');
1846  uicontrol(dlgh, ...
1847      'Style', 'PushButton', ...
1848      'Units', 'Normalized', ...
1849      'String', 'Unselect', ...
1850      'Position', [0.6, 0.14, 0.3, 0.08], ...
1851      'Callback', 'viewedf Channels Unselect');
1852  uicontrol(dlgh, ...
1853      'Style', 'PushButton', ...
1854      'Units', 'Normalized', ...
1855      'String', 'OK', ...
1856      'Position', [0.1, 0.02, 0.3, 0.08], ...
1857      'Callback', 'set(gco,''UserData'',''OK'');uiresume;');
1858  uicontrol(dlgh, ...
1859      'Style', 'PushButton', ...
1860      'Units', 'Normalized', ...
1861      'String', 'Cancel', ...
1862      'Position', [0.6, 0.02, 0.3, 0.08], ...
1863      'Callback', 'set(gco,''UserData'',''Cancel'');uiresume;');
1864  Local.Checkh = [];
1865  set(dlgh, 'UserData', Local);
1866  LocalSelectChannels('Update'); % draw information
1867
1868  drawnow;
1869  uiwait(dlgh);
1870  changed = 0;
1871  Local = get(dlgh, 'UserData');
1872  temp = get(Local.Checkh, 'Value');
1873  Local.Selected{Local.OldWhich} = cat(1,temp{:});
1874  if strcmp(get(gco,'UserData'),'OK')
1875    changed = 1;
1876    for i = 1:length(Data.EDF)
1877      Data.Display.EDF(i).ShowSignals = find(Local.Selected{i});
1878    end
1879    for i = 1:length(Data.Plugin)
1880      Data.Display.Plugin(i).ShowSignals = find(Local.Selected{i+length(Data.EDF)});
1881    end
1882  end
1883  delete(dlgh);
1884  if changed
1885    set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
1886    LocalRepaint(0);
1887  end
1888else
1889  Data=get(gcf,'UserData');
1890  which = get(Data.Poph, 'Value');
1891  switch (Parameter)
1892    case 'Update'
1893      if ~isempty(Data.Checkh)
1894        temp = get(Data.Checkh, 'Value');
1895        if iscell(temp)
1896          Data.Selected{Data.OldWhich} = cat(1,temp{:});
1897        else
1898          Data.Selected{Data.OldWhich} = temp;
1899        end
1900        delete(Data.Checkh);
1901        Data.Checkh = [];
1902      end
1903      Data.OldWhich = which;
1904
1905      cbx = 0.1;
1906      cby = 0.82;
1907      cbxspace = 0.4;
1908      cbyspace = 0.6 / ceil(length(Data.Selected{which}) / 2) + 0.005;
1909      cbwidth = 0.35;
1910      cbheight = LocalGetFontHeight;
1911      for i = 1:length(Data.Selected{which})
1912        Data.Checkh(i) = uicontrol(gcf, ...
1913            'Style', 'CheckBox', ...
1914            'Units', 'Normalized', ...
1915            'String', Data.Label{which}(i, :), ...
1916            'Value', Data.Selected{which}(i), ...
1917            'Position', [cbx + rem(i-1,2)*cbxspace, cby - floor((i-1)/2)*cbyspace, ...
1918              cbwidth, cbheight]);
1919      end
1920    case 'Select'
1921      Data.Selected{which}(:) = 1;
1922      set(Data.Checkh(:), 'Value', 1);
1923    case 'Unselect'
1924      Data.Selected{which}(:) = 0;
1925      set(Data.Checkh(:), 'Value', 0);
1926  end
1927  set(gcf, 'UserData', Data);
1928end
1929
1930%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1931% LocalKeyPress
1932% handle keystrokes
1933function LocalKeyPress()
1934switch upper(get(gcf, 'CurrentCharacter'))
1935  case '+'
1936    feval('viewedf', 'Next');
1937  case '-'
1938    feval('viewedf', 'Prev');
1939  case 'U'
1940    LocalRescaleAll('up');
1941  case 'D'
1942    LocalRescaleAll('down');
1943end
1944
1945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1946% LocalAbout
1947% display program info
1948function LocalAbout()
1949helpdlg(sprintf([ 'EDF (European-Data-Format) file-viewer.\n', ...
1950      'Version 3.04Alpha\n\n' ...
1951      '(c) 1998-2001 Herbert Ramoser\n', ...
1952      '     herbert.ramoser@arcs.ac.at\n\n' ...
1953      'Comments or suggestions may be sent to the author.\n\n', ...
1954      'This Software is subject to the GNU public license.']), ...
1955    'About VIEWEDF');
1956
1957%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1958% LocalHelp
1959% display help page
1960function LocalHelp(Par)
1961name = which('viewedf');
1962name = [ 'file://', name(1:max(find(name == 'm'))-1), 'html'];
1963web(name);
1964
1965%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1966% LocalPrint
1967% display print dialog
1968function LocalPrint()
1969printdlg('-crossplatform', findobj('Tag', 'ViewEDFFigure'));
1970
1971%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972% LocalWatchOn
1973% display watch pointer
1974function LocalWatchOn()
1975set(findobj('Tag', 'ViewEDFFigure'), 'Pointer', 'watch');
1976
1977%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1978% LocalWatchOff
1979% display arrow-pointer
1980function LocalWatchOff()
1981set(findobj('Tag', 'ViewEDFFigure'), 'Pointer', 'arrow');
1982
1983%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1984% LocalGetFontHeight
1985% get Fontheight
1986function hght=LocalGetFontHeight()
1987tempH = uicontrol(...
1988    'Style', 'Text', ...
1989    'String', 'Gg', ...
1990    'Units', 'Normalized', ...
1991    'FontUnits', 'Normalized', ...
1992    'Position', [0, 0, 1, 1], ...
1993    'Visible', 'off');
1994t = get(tempH);
1995hght = getfield(t, 'FontSize') * 1.25; % 1.25 makes things look better
1996delete(tempH);
1997
1998
1999%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2000% LocalGetFontWidth
2001% get Fontwidth
2002function width=LocalGetFontWidth()
2003tempH = uicontrol(...
2004    'Style', 'Text', ...
2005    'String', 'X', ...
2006    'Units', 'Normalized', ...
2007    'FontUnits', 'Normalized', ...
2008    'Position', [0, 0, 1, 1], ...
2009    'Visible', 'off');
2010width = get(tempH, 'Extent');
2011width = width(3);
2012delete(tempH);
2013
2014
2015%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2016% LocalEDFOpen
2017% open a EDF (or GDF) file
2018function LocalEDFOpen(Filename)
2019% show EDF header errors
2020ShowHeadErr = 0;
2021
2022if nargin == 0
2023  % get filename
2024  [edfname,edfpath]=uigetfile('*.*','Open EDF File');
2025  Filename = [edfpath,edfname];
2026  if edfname == 0
2027    return;
2028  end
2029end
2030
2031if 0,
2032%%% becomes obsolete
2033% variables to find things in the header
2034H1idx=[8 80 80 8 8 8 44 8 8 4];
2035H2idx=[16 80 8 8 8 8 8 80 8 32];
2036GDFTYP_BYTE=[1 1 1 2 2 4 4 8 8 4 8 0 0 0 0 0 4 8]';
2037GDFTYPES=[0 1 2 3 4 5 6 7 16 17];
2038
2039fid=fopen(Filename, 'r', 'ieee-le');
2040if (fid < 0)
2041  errordlg('Error reading file', 'File Error');
2042  return
2043end;
2044Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
2045numedf = length(Data.EDF) + 1;
2046
2047% read all data
2048EDFHead.FILE.FID = fid;
2049EDFHead.FILE.OPEN = 1;
2050EDFHead.FileName = Filename;
2051
2052PPos = min([max(find(Filename == '.')) length(Filename) + 1]);
2053SPos = max([0 find(Filename == filesep)]);
2054EDFHead.FILE.Ext = Filename(PPos+1:length(Filename));
2055EDFHead.FILE.Name = Filename(SPos+1:PPos-1);
2056EDFHead.FILE.Path = edfpath;
2057
2058H1 = fread(EDFHead.FILE.FID,184,'uint8=>char')';
2059EDFHead.VERSION = H1(1:8);         % 8 Byte  Versionsnummer
2060IsGDF = strcmp(EDFHead.VERSION(1:3), 'GDF');
2061if (~strcmp(EDFHead.VERSION, '0       ') && ~IsGDF)
2062  errordlg('Unknown file version', 'File error');
2063  return;
2064end
2065EDFHead.PID = deblank(H1(9:88));   % 80 Byte local patient identification
2066EDFHead.RID = deblank(H1(89:168)); % 80 Byte local recording identification
2067if IsGDF                           % handle different file formats
2068  EDFHead.T0 = [str2num(H1(168 + [1:4])) ...
2069        str2num(H1(168 + [5 6])) ...
2070        str2num(H1(168 + [7 8])) ...
2071        str2num(H1(168 + [9 10])) ...
2072        str2num(H1(168 + [11 12])) ...
2073        str2num(H1(168 + [13:16]))];
2074  if str2num(EDFHead.VERSION(4:8)) < 0.12
2075    tmp = fread(EDFHead.FILE.FID, 8, 'uint8=>char')';  % header-length
2076    EDFHead.HeadLen = str2num(tmp);
2077  else
2078    EDFHead.HeadLen = fread(EDFHead.FILE.FID, 1, 'int64');
2079  end
2080  tmp = fread(EDFHead.FILE.FID, 44, 'uchar'); % 44 bytes reserved
2081  EDFHead.NRec = fread(EDFHead.FILE.FID, 1, 'int64');
2082  if strcmp(EDFHead.VERSION(4:8),' 0.10')
2083    EDFHead.Dur =  fread(EDFHead.FILE.FID, 1, 'float64');
2084  else
2085    tmp = fread(EDFHead.FILE.FID, 2, 'uint32');
2086    EDFHead.Dur =  tmp(1)./tmp(2);
2087  end
2088  EDFHead.NS   = fread(EDFHead.FILE.FID, 1, 'uint32');
2089else
2090  EDFHead.T0 = [str2num(H1(168+[7 8])) ...
2091        str2num(H1(168+[4 5])) ...
2092        str2num(H1(168+[1 2])) ...
2093        str2num(H1(168+[9 10])) ...
2094        str2num(H1(168+[12 13])) ...
2095        str2num(H1(168+[15 16])) ];
2096  if EDFHead.T0(1) < 91
2097    EDFHead.T0(1) = 2000 + EDFHead.T0(1);
2098  elseif EDFHead.T0(1) < 100
2099    EDFHead.T0(1) = 1900 + EDFHead.T0(1);
2100  end
2101  H1(185:256) = fread(EDFHead.FILE.FID, 256-184, 'uint8=>char')';
2102  EDFHead.HeadLen = str2num(H1(185:192));  % 8 Byte  Length of Header
2103  EDFHead.NRec = str2num(H1(237:244));     % 8 Byte  # of data records
2104  EDFHead.Dur = str2num(H1(245:252));      % 8 Byte  # duration of data record in sec
2105  EDFHead.NS = str2num(H1(253:256));       % 8 Byte  # of signals
2106end
2107
2108if ~IsGDF
2109  idx1 = cumsum([0 H2idx]);
2110  idx2 = EDFHead.NS * idx1;
2111  h2 = zeros(EDFHead.NS, 256);
2112  H2 = fread(EDFHead.FILE.FID, EDFHead.NS * 256, 'uint8=>char');
2113  H2(H2==0) = 32; % set zero padded strings to blanks
2114  for k = 1:length(H2idx)
2115    h2(:, (idx1(k)+1):idx1(k+1)) = reshape(H2((idx2(k)+1):idx2(k+1)), ...
2116        H2idx(k), EDFHead.NS)';
2117  end
2118  EDFHead.Label      = h2(:, idx1(1)+1:idx1(2));
2119  EDFHead.Transducer = h2(:, idx1(2)+1:idx1(3));
2120  EDFHead.PhysDim    = cellstr(h2(:, idx1(3)+1:idx1(4)));
2121  EDFHead.PhysMin = str2num(h2(:, idx1(4)+1:idx1(5)));
2122  EDFHead.PhysMax = str2num(h2(:, idx1(5)+1:idx1(6)));
2123  EDFHead.DigMin  = str2num(h2(:, idx1(6)+1:idx1(7)));
2124  EDFHead.DigMax  = str2num(h2(:, idx1(7)+1:idx1(8)));
2125  EDFHead.PreFilt = h2(:, idx1(8)+1:idx1(9));
2126  EDFHead.SPR     = str2num(h2(:, idx1(9)+1:idx1(10)));
2127  EDFHead.GDFTYP  = 3*ones(1, EDFHead.NS);
2128else
2129  fseek(EDFHead.FILE.FID, 256, 'bof');
2130  EDFHead.Label      =  fread(EDFHead.FILE.FID, [16,EDFHead.NS], 'uint8=>char')';
2131  EDFHead.Transducer =  fread(EDFHead.FILE.FID, [80,EDFHead.NS], 'uint8=>char')';
2132  EDFHead.PhysDim    =  cellstr(fread(EDFHead.FILE.FID, [8,EDFHead.NS], 'uint8=>char')');
2133  EDFHead.PhysMin    =  fread(EDFHead.FILE.FID, [EDFHead.NS,1], 'float64');
2134  EDFHead.PhysMax    =  fread(EDFHead.FILE.FID, [EDFHead.NS,1], 'float64');
2135  EDFHead.DigMin     =  fread(EDFHead.FILE.FID, [EDFHead.NS,1], 'int64');
2136  EDFHead.DigMax     =  fread(EDFHead.FILE.FID, [EDFHead.NS,1], 'int64');
2137  EDFHead.PreFilt    =  fread(EDFHead.FILE.FID, [80,EDFHead.NS], 'uint8=>char')';
2138  EDFHead.SPR        =  fread(EDFHead.FILE.FID, [1,EDFHead.NS], 'uint32')';
2139  EDFHead.GDFTYP     =  fread(EDFHead.FILE.FID, [1,EDFHead.NS], 'uint32');
2140  tmp = (EDFHead.GDFTYP == 0);
2141  EDFHead.PhysMax(tmp) = 1;
2142  EDFHead.PhysMin(tmp) = 0;
2143  EDFHead.DigMax(tmp)  = 1;
2144  EDFHead.DigMin(tmp)  = 0;
2145end
2146
2147% check validity of DigMin and DigMax
2148if (length(EDFHead.DigMin) ~= EDFHead.NS)
2149  if ShowHeadErr
2150    waitfor(warndlg('Failing Digital Minimum', 'Open EDF file'));
2151  end
2152  EDFHead.DigMin = -(2^15) * ones(EDFHead.NS, 1);
2153end
2154if (length(EDFHead.DigMax) ~= EDFHead.NS)
2155  if ShowHeadErr
2156    waitfor(warndlg('Failing Digital Maximum', 'Open EDF file'));
2157  end
2158  EDFHead.DigMax = (2^15-1) * ones(EDFHead.NS, 1);
2159end
2160if (any(EDFHead.DigMin >= EDFHead.DigMax))
2161  if ShowHeadErr
2162    waitfor(warndlg('Digital Minimum larger than Maximum', ['Open EDF' ...
2163                    ' file']));
2164  end
2165end
2166
2167% check validity of PhysMin and PhysMax
2168if (length(EDFHead.PhysMin) ~= EDFHead.NS)
2169  if ShowHeadErr
2170    waitfor(warndlg('EDFOPEN: Failing Physical Minimum', 'Open EDF file'));
2171  end
2172  EDFHead.PhysMin = EDFHead.DigMin;
2173end
2174if (length(EDFHead.PhysMax) ~= EDFHead.NS)
2175  if ShowHeadErr
2176    waitfor(warndlg('Warning EDFOPEN: Failing Physical Maximum', ['Open EDF' ...
2177                    ' file']));
2178  end
2179  EDFHead.PhysMax = EDFHead.DigMax;
2180end
2181if (any(EDFHead.PhysMin >= EDFHead.PhysMax))
2182  if ShowHeadErr
2183    waitfor(warndlg('EDFOPEN: Physical Minimum larger than Maximum', ['Open' ...
2184                    ' EDF file']));
2185  end
2186  EDFHead.PhysMin = EDFHead.DigMin;
2187  EDFHead.PhysMax = EDFHead.DigMax;
2188end
2189
2190EDFHead.Cal = (EDFHead.PhysMax - EDFHead.PhysMin) ./ (EDFHead.DigMax - ...
2191    EDFHead.DigMin);
2192EDFHead.Off = EDFHead.PhysMin - EDFHead.Cal .* EDFHead.DigMin;
2193tmp = (EDFHead.Cal < 0);
2194EDFHead.Cal(tmp) = 1;
2195EDFHead.Off(tmp) = 0;
2196
2197EDFHead.Calib = [EDFHead.Off'; diag(EDFHead.Cal)];
2198EDFHead.SampleRate = EDFHead.SPR / EDFHead.Dur;
2199
2200bi = [0; cumsum(EDFHead.SPR)];
2201EDFHead.AS.spb = sum(EDFHead.SPR);
2202EDFHead.AS.bi = bi;
2203EDFHead.AS.bpb = sum(EDFHead.SPR .* GDFTYP_BYTE(EDFHead.GDFTYP+1));
2204EDFHead.AS.GDFbi = [0; cumsum(EDFHead.AS.bpb)];
2205
2206EDFHead.Chan_Select = (EDFHead.SPR == max(EDFHead.SPR));
2207for k = 1:EDFHead.NS
2208  if EDFHead.Chan_Select(k)
2209    EDFHead.ChanTyp(k) = 'N';
2210  else
2211    EDFHead.ChanTyp(k) = ' ';
2212  end;
2213  if findstr(upper(EDFHead.Label(k,:)), 'ECG')
2214    EDFHead.ChanTyp(k) = 'C';
2215  elseif findstr(upper(EDFHead.Label(k,:)), 'EKG')
2216    EDFHead.ChanTyp(k) = 'C';
2217  elseif findstr(upper(EDFHead.Label(k,:)), 'EEG')
2218    EDFHead.ChanTyp(k) = 'E';
2219  elseif findstr(upper(EDFHead.Label(k,:)), 'EOG')
2220    EDFHead.ChanTyp(k) = 'O';
2221  elseif findstr(upper(EDFHead.Label(k,:)), 'EMG')
2222    EDFHead.ChanTyp(k) = 'M';
2223  elseif findstr(upper(EDFHead.Label(k,:)), 'RESP')
2224    EDFHead.ChanTyp(k) = 'R';
2225  end
2226end
2227
2228fseek(EDFHead.FILE.FID, 32 * EDFHead.NS, 0);
2229if EDFHead.NRec == -1   % unknown record size, determine correct NRec
2230  fseek(EDFHead.FILE.FID, 0, 'eof');
2231  endpos = ftell(EDFHead.FILE.FID);
2232  EDFHead.NRec = floor((endpos - EDFHead.HeadLen) / (sum(EDFHead.AS.bpb)));
2233end
2234fseek(EDFHead.FILE.FID, EDFHead.HeadLen, 'bof');
2235else
2236	EDFHead = sopen(Filename,'r',0,'OVERFLOWDETECTION:OFF FORCEALLCHANNEL');
2237	EDFHead.Dur = EDFHead.SPR/EDFHead.SampleRate;
2238	EDFHead.PhysDim = physicalunits(EDFHead.PhysDimCode);
2239
2240	Data   = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
2241	numedf = length(Data.EDF) + 1;
2242end;
2243
2244Data.EDF(numedf).Head = EDFHead;
2245drawnow;
2246set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
2247LocalResetDisplay;
2248
2249%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2250% LocalEDFRead
2251% read data from EDF file
2252function [Record, EDFHead] = LocalEDFRead(EDFHead, recinfo)
2253
2254startrec = recinfo(1);
2255numrec = recinfo(2);
2256
2257
2258if 0,
2259%%% obsolete ???
2260
2261% define GDF data types
2262GDF_STRING = {'uchar', 'int8', 'uint8', 'int16', 'uint16', 'int32', ...
2263      'uint32', 'int64', 'uint64', '', '', '', '', '', '', '', 'float32', ...
2264      'float64'};
2265
2266GDF_STRING{256+24} = 'bit24';
2267GDF_STRING{512+24} = 'ubit24';
2268
2269if LocalEDFSeek(EDFHead, startrec, 'bof') < 0
2270  if numrec ~= 0
2271    waitfor(warndlg('Can not seek start record', 'Read EDF data'));
2272  end
2273  Record = {};
2274  return;
2275end
2276
2277LocalWatchOn;
2278
2279RecLen = max(EDFHead.SPR);
2280for rec = 1:numrec
2281  for ch = 1:EDFHead.NS
2282    [d, count] = fread(EDFHead.FILE.FID, EDFHead.AS.SPR(ch), ...
2283        GDF_STRING{EDFHead.GDFTYP(ch)+1});
2284    if count < 1
2285      break;
2286    end
2287    S(EDFHead.AS.bi(ch)+1:EDFHead.AS.bi(ch+1), rec) = d;
2288  end
2289  if count < 1
2290    numrec = rec;
2291    waitfor(warndlg(sprintf('Can not read %i records', numrec), 'Read EDF data'));
2292    break
2293  end
2294end
2295
2296for ch = 1:EDFHead.NS
2297  S(EDFHead.AS.bi(ch)+1 : EDFHead.AS.bi(ch+1),:) = S(EDFHead.AS.bi(ch)+1 : ...
2298      EDFHead.AS.bi(ch+1),:) * EDFHead.Cal(ch) + EDFHead.Off(ch);
2299end
2300
2301for ch = 1:EDFHead.NS,
2302  Record{ch} = reshape(S(EDFHead.AS.bi(ch)+1 : EDFHead.AS.bi(ch+1),:), ...
2303      EDFHead.AS.SPR(ch) * numrec, 1);
2304end
2305EDFHead.AS.numrec = numrec;
2306EDFHead.AS.startrec = startrec;
2307LocalWatchOff;
2308
2309else
2310LocalWatchOn;
2311
2312	Dur = EDFHead.SPR/EDFHead.SampleRate;
2313	[s,EDFHead] = sread(EDFHead,numrec*Dur,startrec*Dur);
2314	for ch = 1:EDFHead.NS,
2315		Record{ch} = s(:,ch);
2316	end;
2317
2318LocalWatchOff;
2319end
2320
2321%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2322% LocalEDFSeek
2323% change position in EDF file
2324function [status] = LocalEDFSeek(EDFHead, offset, origin)
2325if (origin == -1) || (origin == 'bof'),
2326  offset = EDFHead.HeadLen + EDFHead.AS.bpb * offset;
2327  status = fseek(EDFHead.FILE.FID, offset, origin);
2328elseif (origin == 0) || (origin == 'cof'),
2329  offset = EDFHead.AS.bpb * offset;
2330  status = fseek(EDFHead.FILE.FID, offset, origin);
2331elseif (origin == 1) || (origin == 'eof'),
2332  offset = EDFHead.HeadLen + EDFHead.AS.bpb * (EDFHead.NRec + offset);
2333  status = fseek(EDFHead.FILE.FID, offset, -1);
2334end;
2335
2336%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2337% LocalEDFClose
2338% close an EDF file
2339function LocalEDFClose()
2340Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
2341if length(Data.EDF)==0
2342  errordlg('No EDF-File is open!', 'Error');
2343  return;
2344end
2345
2346[ind, cancelled] = LocalSelectEDFFile({'Close EDF file', 'Close file'}, Data.EDF);
2347if cancelled
2348  return
2349end
2350
2351%fclose(Data.EDF(ind).Head.FILE.FID);
2352sclose(Data.EDF(ind).Head);
2353
2354for i = ind:(length(Data.EDF)-1)
2355  Data.Display.EDF(i) = Data.Display.EDF(i+1);
2356  Data.EDF(i) = Data.EDF(i+1);
2357end
2358numedf = length(Data.EDF)-1;
2359if numedf == 0
2360  Data.EDF = [];
2361  Data.Display.EDF = [];
2362else
2363  Data.EDF = Data.EDF(1:numedf);
2364  Data.Display.EDF = Data.Display.EDF(1:numedf);
2365end
2366set(findobj('Tag', 'ViewEDFFigure'), 'UserData', Data);
2367% take care of plugins
2368if (length(Data.Plugin) > 0)
2369  waitfor(warndlg('All plugins using the closed EDF file will be removed', ...
2370      'Close warning'));
2371  for i = length(Data.Plugin):-1:1
2372    if (Data.Plugin(i).EDFFile == ind)
2373      LocalRemovePlugin(i);
2374    end
2375  end
2376end
2377LocalRepaint;
2378
2379
2380%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2381% LocalSelectEDFFile
2382% display dialog to select a loaded EDF file
2383function [FileNum, Cancelled] = LocalSelectEDFFile(Title, EDFData)
2384dlgh = dialog(...
2385    'Name', Title{1}, ...
2386    'CloseRequestFcn', 'set(gcf,''UserData'',''Cancel'');uiresume;');
2387dlgpos = get(dlgh, 'Position');
2388set(dlgh, 'Position', [dlgpos(1),dlgpos(2),300,100]);
2389
2390EDFNames = {};
2391% get EDF FIle names
2392for i = 1:length(EDFData)
2393  EDFNames = {EDFNames{:}, EDFData(i).Head.FileName};
2394end
2395
2396poph = uicontrol(dlgh, ...
2397    'Style', 'Popup', ...
2398    'Units', 'Normalized', ...
2399    'String',EDFNames, ...
2400    'Value', 1, ...
2401    'Position', [0.05, 0.5, 0.9, 0.35]);
2402% buttons
2403uicontrol(dlgh, ...
2404    'Style', 'PushButton', ...
2405    'Units', 'Normalized', ...
2406    'String', Title{2}, ...
2407    'Position', [0.1, 0.05, 0.3, 0.3], ...
2408    'Callback', 'set(gco,''UserData'',''OK'');uiresume;');
2409uicontrol(dlgh, ...
2410    'Style', 'PushButton', ...
2411    'Units', 'Normalized', ...
2412    'String', 'Cancel', ...
2413    'Position', [0.6, 0.05, 0.3, 0.3], ...
2414    'Callback', 'set(gco,''UserData'',''Cancel'');uiresume;');
2415
2416drawnow;
2417uiwait(dlgh);
2418if strcmp(get(gco,'UserData'),'OK')
2419  Cancelled = 0;
2420  FileNum = get(poph, 'Value');
2421else
2422  Cancelled = 1;
2423  FileNum = 0;
2424end
2425delete(dlgh);
2426
2427%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2428% LocalCloseViewEDF
2429% close viewer
2430function LocalCloseViewEDF()
2431Data = get(findobj('Tag', 'ViewEDFFigure'), 'UserData');
2432% close all files
2433for i = 1:length(Data.EDF);
2434  %fclose(Data.EDF(i).Head.FILE.FID);
2435  sclose(Data.EDF(i).Head);
2436end
2437delete(findobj('Tag', 'ViewEDFFigure'));
2438