% READEGI - read EGI Simple Binary datafile (versions 2,3,4,5,6,7).
% Return header info, EEG data, and any event data.
% Usage:
% >> [head, TrialData, EventData, CatIndex] = readegi(filename, dataChunks, forceversion)
%
% Required Input:
% filename = EGI data filename
%
% Optional Input:
% dataChunks = vector containing desired frame numbers(for unsegmented
% datafiles) or segments (for segmented files). If this
% input is empty or is not provided then all data will be
% returned.
% forceversion = integer from 2 to 7 which overrides the EGI version read from the
% file header. This has been occasionally necessary in cases where
% the file format was incorrectly indicated in the header.
% Outputs:
% head = struct containing header info (see READEGIHDR )
% TrialData = EEG channel data
% EventData = event codes
% CatIndex = segment category indices
%
% Author: Cooper Roddey, SCCN, 13 Nov 2002
%
% Note: code derived from C source code written by
% Tom Renner at EGI, Inc.
%
% See also: READEGIHDR
% Copyright (C) 2002 , Salk Institute, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.
function [head, TrialData, EventData, SegmentCatIndex] = readegi(filename, dataChunks,forceversion)
if nargin <1 || nargin > 3,
help readegi;
return;
end
if nargout < 2 || nargout > 4,
error('2 to 4 output args required');
end
if ~exist('dataChunks','var')
dataChunks = [];
end
if ~isvector(dataChunks)
error('dataChunks must either be empty or a vector');
end
[fid,message] = fopen(filename,'rb','b');
if (fid < 0),
error(message);
end
% get our header structure
fprintf('Importing binary EGI data file ...\n');
if exist('forceversion')
head = readegihdr(fid,forceversion);
else
head = readegihdr(fid);
end
% do we have segmented data?
segmented = 0;
switch(head.version),
case {2,4,6}
segmented = 0;
case {3,5,7}
segmented = 1;
end
% each type of event has a dedicated "channel"
FrameVals = head.nchan + head.eventtypes;
if (segmented)
desiredSegments = dataChunks;
if isempty(desiredSegments),
desiredSegments = [1:head.segments];
end
nsegs = length(desiredSegments);
TrialData = zeros(FrameVals,head.segsamps*nsegs);
readexpected = FrameVals*head.segsamps*nsegs;
else
desiredFrames = dataChunks;
if isempty(desiredFrames),
desiredFrames = [1:head.samples];
end
nframes = length(desiredFrames);
TrialData = zeros(FrameVals,nframes);
readexpected = FrameVals*nframes;
end
% get datatype from version number
switch(head.version)
case {2,3}
datatype = 'integer*2';
case {4,5}
datatype = 'float32';
case {6,7}
datatype = 'float64';
otherwise,
error('Unknown data format');
end
% read in epoch data
readtotal = 0;
j=0;
SegmentCatIndex = [];
if (segmented),
for i=1:head.segments,
segcatind = fread(fid,1,'integer*2');
segtime = fread(fid,1,'integer*4');
[tdata, count] = ...
fread(fid,[FrameVals,head.segsamps],datatype);
% check if this segment is one of our desired ones
if ismember(i,desiredSegments)
j=j+1;
SegmentCatIndex(j) = segcatind;
SegmentStartTime(j) = segtime;
TrialData(:,[1+(j-1)*head.segsamps:j*head.segsamps]) = tdata;
readtotal = readtotal + count;
end
if (j >= nsegs), break; end
end
else
% read unsegmented data
% if dataChunks is empty, read all frames
if isempty(dataChunks)
[TrialData, readtotal] = fread(fid, [FrameVals,head.samples],datatype);
else % grab only the desiredFrames
% This could take a while...
for i=1:head.samples,
[tdata, count] = fread(fid, [FrameVals,1],datatype);
% check if this segment is a keeper
if ismember(i,desiredFrames),
j=j+1;
TrialData(:,j) = tdata;
readtotal = readtotal + count;
end
if (j >= nframes), break; end
end
end
end
fclose(fid);
if ~isequal(readtotal, readexpected)
error('Number of values read not equal to the number expected.');
end
EventData = [];
if (head.eventtypes > 0),
EventData = TrialData(head.nchan+1:end,:);
TrialData = TrialData(1:head.nchan,:);
end
% convert from A/D units to microvolts
if ( head.bits ~= 0 && head.range ~= 0 )
TrialData = (head.range/(2^head.bits))*TrialData;
end
% convert event codes to char
% ---------------------------
head.eventcode = char(head.eventcode);
%--------------------------- ISVECTOR ---------------
function retval = isvector(V)
s = size(V);
retval = ( length(s) < 3 ) & ( min(s) <= 1 );
%------------------------------------------------------