-
Notifications
You must be signed in to change notification settings - Fork 16
/
mff_importsignal.m
296 lines (256 loc) · 13.5 KB
/
mff_importsignal.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
% mff_importsignal - import information from MFF 'signal1.bin' file
%
% Usage:
% data = mff_importsignal(mffFile, skipdataflag);
%
% Inputs:
% mffFile - filename/foldername for the MFF file
% skipdataflag - [0|1] skip data flag, when set to 1, the data is not imported
% default is 0.
%
% Output:
% data - cell array of raw data (one cell is one block in the original
% mff framework)
% datasize - size of each block
% srate - sampling rate
% npns - number of PNS data channels
% This file is part of mffmatlabio.
%
% mffmatlabio is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% mffmatlabio is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with mffmatlabio. If not, see <https://www.gnu.org/licenses/>.
function [floatData, allDataSize, frequencies, nChannels] = mff_importsignal(mffFile)
if nargin < 1
help mff_importsignal;
return;
end
if exist('eegplugin_mffimport')
error('MFFimport plugin conflict detected, remove plugin and call back this function/menu');
end
mff_path;
% Create a factory.
mfffactorydelegate = javaObject('com.egi.services.mff.api.LocalMFFFactoryDelegate');
mfffactory = javaObject('com.egi.services.mff.api.MFFFactory', mfffactorydelegate);
binfilenames = { [mffFile filesep 'signal1.bin'] [mffFile filesep 'signal2.bin'] };
if ~exist(binfilenames{2}) binfilenames(2) = []; end
floatData = { [] [] };
allDataSize = { [] [] };
nChannels = [0 0];
for iFile = 1:length(binfilenames)
% Create Signal object and read in signal1.bin file.
signalresourcetype = javaObject('com.egi.services.mff.api.MFFResourceType', javaMethod('valueOf', 'com.egi.services.mff.api.MFFResourceType$MFFResourceTypes', 'kMFF_RT_Signal'));
signalResource = mfffactory.openResourceAtURI(binfilenames{iFile}, signalresourcetype);
rVal = true;
if ~isempty(signalResource)
%try
res = signalResource.loadResource();
if res
blocks = signalResource.getSignalBlocks();
numblocks = signalResource.getNumberOfBlocks();
if ~isempty(blocks)
% before reading any data, look at info for each block
blockIndex = 0;
for x = 0:numblocks-1
block = blocks.get(x);
if rVal
% Load the signal Blocks data
try
block = signalResource.loadSignalBlockData(block);
catch
errorCode = lasterror;
if strcmpi(errorCode.identifier, 'MATLAB:Java:GenericException')
error( [ 'You must increase Java Memory to read this file' 10 ...
'On the Home tab, in the Environment section, click Preferences.' 10 ...
'Select MATLAB > General > Java Heap Memory' 10 ...
'You must restart Matlab after making this change.' 10 ...
'If your Java memory is already at the maximum, the easiest' 10 ...
'solution is to use another computer to import the file' ]);
else
error(lasterr);
end
end
version = block.version;
dataSize = block.dataBlockSize;
allDataSize{iFile}(x+1) = dataSize;
nChannels(iFile) = block.numberOfSignals;
nSamples = 0;
headerSize = block.headerSize;
offsets = block.offsets; % int array
signalDepth = block.signalDepth; % int array
frequencies = block.signalFrequency; % int array
if isempty(offsets) || isempty(signalDepth) || isempty(frequencies)
error('Error: Arrays are null for block no. %d\n', blockIndex);
end
typeSize = (signalDepth(1) / 8); % 8 bits
% Determine the number of sample. Note the special check for only one channel.
if ~isempty(offsets) && nChannels(iFile) > 1
nSamples = offsets(2) / typeSize;
else
if(nChannels(iFile) == 1)
nSamples = dataSize / typeSize;
end
end
if(blockIndex == 0)
fprintf('Signal Block Version Number: %d\n', version);
fprintf('Signal Block Data Size: %d\n', dataSize);
fprintf('Signal Block Header size. %d\n', headerSize);
fprintf('Number of Signals: %d\n', nChannels(iFile));
fprintf('Signal Block Samples: %d\n', nSamples);
fprintf('Sample Rate: %d\n', frequencies(1));
fprintf('Signal Depth: %d\n', signalDepth(1));
fprintf('---------------------------------\n');
% Optional Header is usually only written to the
% first signal block of the signal file.
if ~isempty(block.optionalHeader)
buffer = typecast(block.optionalHeader,'uint8');
% Get the optional headers information. Please refer to the
% Meta File Format(MFF)documentation for more information about
% Signal files and the optional header.
tmpType = typecast(buffer(1:4),'int32');
numBlocks = typecast(buffer(5:12),'int64');
totalSamples = typecast(buffer(13:20),'int64');
numSignals = typecast(buffer(21:24),'int32');
fprintf('Optional Header type: %d\n',tmpType);
fprintf('Optional Header number of blocks total: %d\n',numBlocks);
fprintf('Optional Header number of Samples total: %d\n',totalSamples);
fprintf('Optional Header number of Signals: %d\n',numSignals);
fprintf('------------------------------------------\n');
end
end
% Get the data.
typeSize = 4;
floatData{iFile}{blockIndex+1} = typecast(block.data,'single'); % WARNING LITTLE ENDIAN HERE
% Note: the length of the buffer should match the Block data size.
if length(floatData{iFile}{blockIndex+1})*typeSize ~= dataSize
error('Error: Data buffer size mismatch\n');
end
floatData{iFile}{blockIndex+1} = reshape(floatData{iFile}{blockIndex+1}, nSamples, nChannels(iFile))';
%---
% Note: offsets[] are represented in bytes. what we want is a value we can use as an
% offset in our signalArray for the given datatype: int, float , double. To do this we need
% to calculate: int offset = ( offsets[channelnumber] / typeSize ), or with the actual
% array: float someVal = signalArray[( offsets[channelnumber] / typeSize )].
%---
% A few examples of accessing the data. %
% Get first sample from each channel in this signal block.
% for channel = 1:nChannels
% offset = offsets(channel);
% fprintf('First Sample for channel no. %d : %f\n', channel, floatData(offset/typeSize +1));
% end
%Get every sample for every channel from float array.
% for c=1:nChannels
% fprintf('Block No. %d Channel No: %d\n', blockIndex, c);
% for s=1:nSamples
% signalVal = floatData((offsets(c)/typeSize) + s);
% fprintf(' Sample No. %d:%f\n', s, signalVal);
% end
% end
%
% % Get every channel for every sample from float array.
% for s=1:nSamples
% fprintf('Block No. "+blockIndex+" Sample No. %d\n',s);
% for c=1:nChannels
% signalVal = floatData((offsets(c)/typeSize) + s);
% fprintf(' Channel No. %d:%f\n', c, signalVal);
% end
% end
else
error('Error Accessing signal data.\n');
end
blockIndex = blockIndex+1;
end
else
error('Error: Empty block.\n');
end
else
error('Error: Could not load the signal resource.\n');
end
%catch
% Logger.getLogger(MFFAPIExamples.class.getName()).log(Level.SEVERE, null, ex);
% rVal = false;
% Additional cleanup as needed
%end
else
error('Error: Can not open the signal resource.\n');
end
mfffactory.closeResource(signalResource);
end
% combine autonomous and EEG data
if ~isempty(floatData{2})
% remove last channel of PNS data if null
uniqueLastChan = unique(floatData{2}{1}(end,:));
if length(uniqueLastChan) == 1 && uniqueLastChan == 0
floatData{2} = cellfun(@(x)x(1:end-1,:), floatData{2}, 'uniformoutput', false);
end
nChannels(2) = size(floatData{2}{1},1);
% concatenate PNS data and EEG data
try
for iSegment = 1:length(floatData{1})
floatData{1}{iSegment} = [ floatData{1}{iSegment}; floatData{2}{iSegment} ];
end
catch
error('Issue with concatenating the autonomous data and the EEG data');
end
floatData = floatData{1};
allDataSize = allDataSize{1} + allDataSize{2};
else
floatData = floatData{1};
allDataSize = allDataSize{1};
end
% % Inspect Signal file. How many blocks, samples, etc.
% % This can be done without reading in any of the actual data.
%
% % Get first block, returned as bytes. Will convert to single precision
% % floating point values later.
% blocks = binObj.getSignalBlocks();
% numblocks = binObj.getNumberOfBlocks()
%
% % before reading any data, look at info for each block
% for x = 0:numblocks-1
% blockObj = blocks.get(x);
% blockObj.version
% blockObj.headerSize
% blockObj.dataBlockSize
% blockObj.numberOfSignals
% blockObj.optionalHeaderSize
% samplesinblock = blockObj.dataBlockSize
% end
%
% % Read the first block and plot the data for the first two channels
% if numblocks >= 1
% blockObj = blocks.get(0)
%
% % To access the data for a block, it must be loaded first.
% blockObj = binObj.loadSignalBlockData(blockObj)
% bytearray = blockObj.data;
% sizebytearray = size(bytearray)
%
% % Number of 4 byte floats is 1/4 the data block size that
% % is divided by channel count to get data for each channel:
% samplesinblock = blockObj.dataBlockSize/4
% channelsize = samplesinblock / blockObj.numberOfSignals
%
% % Convert bytes to equivalent floating point values.
% floatdata = typecast(bytearray,'single');
% sizeofdata = size(floatdata)
% floatdata(1:channelsize)
% floatdata(channelsize+1:2*channelsize)
%
% % Plot results if desired
% if plotresults
% figure;
% hold on
%
% subplot(2,1,1); plot( 1:channelsize, floatdata(1:channelsize) )
% subplot(2,1,2); plot( 1:channelsize, floatdata(channelsize+1:2*channelsize) )
% end
% end