function [time_arr,event_arr,eog_arr,epp_arr,header,trialcount,header2] = readcortex(filename) % function to read the cortex datafile % and put the timecodes, eventcodes, trialheaders % in an array of arrays, and the nr of trials in a scalar. % - - - % USAGE: [times,events,eog_arr,epp_arr,header,trialcount,header2] = readcortex(path\file_name) % - - - % adapted from get_ALLdata.m % % GDLH modified this 5/16/00 -- no need to preallocate the sizes of the arrays % Matlab 5.2 will automatically pad with zeros when necessary. How convenient! % (But preallocating does seem to speed things up a bit.) % % GDLH modified this 4/2/01 -- Now returning the eog_arr as well. % % GDLH modified this 4/28/01 -- if we hit an error in the datafile, just % return what we can. % % MAS modified this 8/16/04 -- added in extra code to pull out the % header from the new write_header() function in the timing file. % Also changed use of "length" to "flength" for better compatibility. % % MAS modified this 10/15/04 -- Changed the fopen statement to use % little endian, and added an error-checking statement in case there % is an endian error. Also fixed an error in the write_header() reading % code MAXNUMTRIALS = 1000; trialcount = 0; % Old fopen statement: %fid = fopen(filename, 'rb'); fid = fopen(filename, 'r','ieee-le'); %fid = fopen(filename, 'r','ieee-be'); if (fid == -1) error(['Cannot open file: ',filename]); end time_arr = zeros(1, MAXNUMTRIALS); % array of time_code arrays event_arr = zeros(1, MAXNUMTRIALS); % array of event_code arrays eog_arr = zeros(1, MAXNUMTRIALS); % array of eog_code arrays eog_lengths = []; epp_arr = zeros(1, MAXNUMTRIALS); % array of epp_code arrays epp_lengths = []; header = zeros(13, MAXNUMTRIALS); % array of trial headers header2 = []; hd=zeros(1,13); % a single header (read every trial) while (~feof (fid)) flength = fread(fid, 1, 'unsigned short'); if (isempty(flength)~=1) hd(1,1:8)= (fread(fid, 8, 'unsigned short'))'; hd(1,9:10) = (fread(fid, 2, 'unsigned char'))'; hd(1,11:13)= (fread(fid, 3, 'unsigned short'))'; hd(1,5)=hd(1,5)/4; % reduce the size of the time_code array hd(1,6)=hd(1,6)/2; % idem for event_code array hd(1,7)=hd(1,7)/2; % and eogs hd(1,8)=hd(1,8)/2; % and epp (not used) % This helps detect endian errors when opening the file %hddiff = hd - floor(hd); %if (~isempty(find(hddiff ~= 0))) if (sum(floor(hd) - hd) ~= 0) error('READCORTEX: Header data contains non-integers, endian needs to be changed'); end % read the time codes, event_codes, eogs and epps (if any) for this trial try time_arr(1:(hd(1,5)),trialcount+1) = (fread (fid,(hd(1,5)) , 'unsigned long')); event_arr(1:(hd(1,6)),trialcount+1) = (fread (fid,(hd(1,6)), 'unsigned short')); % epp array is stored in the data file before the eog array epp_arr(1:(hd(1,8)),trialcount+1) = fread (fid,(hd(1,8)), 'short'); % must modify all epp entries for i = 1:1:(hd(1,8)), % Must extract the data from the raw epp values. % The epp value is made up of 12-bits of data, and 4-bits (the % low-order 4 bits) of the channel number. % To extract the data, must right shift the raw data by 4 bits (to % get rid of the channel number and put the data value in the proper % location). After this conversion, you must still add or subtract % 2048, since otherwise the value is not right. (I think that this % is because of the way that matlab handles negative values during % the bitwise operations.) % These calculations cause the results of ctx2txt.m to be the same as % for cortview.exe for the EOG and EPP values. eppdata = bitshift(epp_arr(i, trialcount+1), -4); if (eppdata < 0) eppdata = eppdata + 2047; else eppdata = eppdata - 2048; end; epp_arr(i, trialcount+1) = eppdata; end; epp_lengths(trialcount+1) = hd(1,8); eog_arr(1:(hd(1,7)),trialcount+1) = (fread (fid,(hd(1,7)), 'short')); eog_lengths(trialcount+1) = hd(1,7); % put this trial's header in the header_array header(1:13,trialcount+1)=hd(1,1:13)'; trialcount = trialcount+1; catch break; end; end; end; fclose(fid); time_arr(:,[trialcount+1:end]) = []; event_arr(:,[trialcount+1:end]) = []; eog_arr(:,[trialcount+1:end]) = []; epp_arr(:,[trialcount+1:end]) = []; header(:,[trialcount+1:end]) = []; if (size(eog_arr,1) == 1) eog_arr = []; else % 'nan' padding the eog_ary for i = 1:trialcount %i %eog_lengths(i) %size(eog_arr) if (eog_lengths(i) < size(eog_arr,1)) eog_arr([eog_lengths(i)+1:end],i) = nan; end end end if (size(epp_arr,1) == 1) epp_arr = []; else % 'nan' padding the epp_arr for i = 1:trialcount if (epp_lengths(i) < size(epp_arr,1)) epp_arr([epp_lengths(i)+1:end],i) = nan; end end end %%%%% Added by MAS to decode the special write_header() info %%%%% if (nargout > 6) % only run this if the user specifies they want "header2" first_trial = event_arr(:,1); i = find (first_trial < 256); if (~isempty(i) && (first_trial(1) == 65535)) % If the first code sent is 65535, that's a marker % to indicate there is write_header() data t = first_trial(1:min(i)-1); for I=1:length(t) t2(2*I) = floor(t(I)/256); t2(2*I-1) = mod(t(I),256); end % add a trailing 255 if necessary to help with parsing the header if (t2(length(t2)) ~= 255) t2(length(t2)+1) = 255; end % 255 is used to space out the data in the header j = find(t2 == 255); % if the header starts with 3 255's, cut it down to 2. if (sum(t2(1:3)) == 765) j(1) = []; end % Get the required header data header2.data_file = char(t2(j(2)+1:j(3)-1)); header2.cnd_file = char(t2(j(3)+1:j(4)-1)); header2.ext_file = char(t2(j(4)+1:j(5)-1)); header2.item_file = char(t2(j(5)+1:j(6)-1)); header2.css_file = char(t2(j(6)+1:j(7)-1)); header2.xdim = char(t2(j(7)+1:j(8)-1)); header2.ydim = char(t2(j(8)+1:j(9)-1)); header2.fps = char(t2(j(9)+1:j(10)-1)); header2.hpix = char(t2(j(10)+1:j(11)-1)); header2.vpix = char(t2(j(11)+1:j(12)-1)); header2.bpp = char(t2(j(12)+1:j(13)-1)); % Get the extern header data (if it's present) num_externs = ceil((length(j) - 13 - 1)/2); if (num_externs > 0) header2.ext_name = cell(num_externs,1); header2.ext_val = cell(num_externs,1); for I=1:(num_externs*2) if (mod(I,2) == 1) namestart = j(13+I-1)+1; namestop = j(13+I)-1; header2.ext_name{floor(I/2)+1} = char(t2(namestart:namestop)); end if (mod(I,2) == 0) valstart = j(13+I-1)+1; valstop = j(13+I)-1; header2.ext_val{I/2} = char(t2(valstart:valstop)); end end end end end