Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

saveNEV.m 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. function saveNEV(NEV, varargin)
  2. %%
  3. % Save an .NEV file from an NEV structure (gained by using openNEV)
  4. % Works with file spec 2.3
  5. %
  6. % Use saveNEV(NEV, filename, noreport)
  7. % All input arguments are optional. Input arguments can be in any order.
  8. %
  9. % NEV: Name of the NEV structure to be saved.
  10. % DEFAULT: The workspace NEV structure in the workspace will
  11. % be saved.
  12. %
  13. % filename: Name of the new NEV file name.
  14. % DEFAULT: -out.nev will be added to the end of the current
  15. % file name.
  16. %
  17. % 'noreport': Will not display status reports or warnings.
  18. % DEFAULT: will display status reports and warnings.
  19. %
  20. %
  21. % OUTPUT: None
  22. %
  23. % Example 1:
  24. % saveNEV
  25. %
  26. % In the example above, a new file containing the NEV structure in the
  27. % workspace will be saved. The file name will have -out.NEV added to its
  28. % name. Statuses of the progress of saveNEV and also warnings about the
  29. % risks of saving will be displayed.
  30. %
  31. % Example 2:
  32. % openNSx(NEV, 'myNewNEVFile.nev', 'noreport');
  33. %
  34. % In the example above, a new file containing the NEV structure in the
  35. % workspace will be saved. The file name will be myNewNEVFile.nev.
  36. % Statuses of the progress of saveNEV and also warnings about the
  37. % risks of saving will be not be displayed.
  38. %
  39. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  40. % Nick Halper
  41. % support@blackrockmicro.com
  42. % Blackrock Microsystems
  43. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  44. % Version History
  45. %
  46. % 1.0.0.0: Nick Halper
  47. % - Initial release.
  48. %
  49. % 1.1.0.0: Kian Torab
  50. % - Added the ability to suppress the fiel saving warning with
  51. % 'noreport' input parameter.
  52. % - Re-structured help to better match the suite's style. Added examples.
  53. % - Added the 'noreport' key to supress statuses and warnings.
  54. % - Improved error checking for input arguments.
  55. %
  56. % 1.2.0.0: Nick Halper - 19/8/29
  57. % - Allows saveNEV to dynamically determine header offset and total
  58. % number of extended headers instead of relying on info in MetaTags/Raw
  59. % Data of NEV structure.
  60. % - Fixed a bug where choosing to overwrite would crash the script
  61. % - Fixed an issue where bank letters were not being written correctly, writing
  62. % blank values
  63. % - Modified the script to work with 256 channel files
  64. %
  65. % 1.3.0.0: Stephen hou - 19/8/30
  66. % - Implemented saving of files that contain NeuroMotive/tracking data
  67. %
  68. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  69. % Verify FilePath and establish overwrite paramaters
  70. if not(NEV.MetaTags.FileSpec == '2.3')
  71. disp(strcat('This function only functions on file spec 2.3,;this is your file spec:',NEV.MetaTags.FileSpec));
  72. return
  73. end
  74. if nargin > 1
  75. for idx = 1:nargin-1
  76. if strcmpi(varargin{idx}, 'noreport')
  77. reportFlag = 0;
  78. elseif length(varargin{idx})>3 && ...
  79. (strcmpi(varargin{idx}(3),'\') || ...
  80. strcmpi(varargin{idx}(1),'/') || ...
  81. strcmpi(varargin{idx}(2),'/') || ...
  82. strcmpi(varargin{idx}(1:2), '\\'))
  83. FilePath = varargin{1};
  84. end
  85. end
  86. end
  87. % Validating input arguments
  88. if ~exist('FilePath', 'var'); FilePath = [fullfile(NEV.MetaTags.FilePath,NEV.MetaTags.Filename) '-out.nev']; end
  89. if ~exist('reportFlag', 'var'); reportFlag = 1; end;
  90. % Warning user about the consequences of the modified NEV file
  91. if reportFlag
  92. Accept = input('This script will save a new file with the .NEV extensions, but you should retain the previous file. Do you acknowledge the risk inherent in saving modified versions of data files? (Y/N)','s');
  93. if ~strcmpi(Accept,'y')
  94. disp('Ending Script...');
  95. return
  96. end
  97. end
  98. % Validating and opening the writable file
  99. if exist(FilePath)
  100. if exist(FilePath)
  101. disp('File already exists!');
  102. OverwritePrompt = input('Would you like to overwrite? (Y/N)','s');
  103. if strcmpi(OverwritePrompt,'y')
  104. Overwrite = 1;
  105. delete(FilePath);
  106. else
  107. while exist(FilePath)
  108. ExistCount = ExistCount + 1;
  109. FilePath = fullfile(NEV.MetaTags.FilePath,[NEV.MetaTags.Filename '-Aligned-',num2str(ExistCount),NEV.MetaTags.FileExt]);
  110. end
  111. end
  112. end
  113. end
  114. FileID = fopen(FilePath, 'w', 'ieee-le');
  115. if (FileID <= 0)
  116. disp('No file was selected.');
  117. return;
  118. end
  119. %% Write the basic header into the file
  120. % General warining about the length of time it takes to save a NEV file so
  121. % the user does not abort the process
  122. disp(['Saving NEV file ' FilePath '. This can take a long time. Please be patient.']);
  123. if reportFlag; disp('Writing Basic Header...'); end
  124. fwrite(FileID,NEV.MetaTags.FileTypeID(1:8));
  125. fwrite(FileID, [str2double(NEV.MetaTags.FileSpec(1)) str2double(NEV.MetaTags.FileSpec(3))], 'uint8');
  126. fwrite(FileID,str2double(NEV.MetaTags.Flags),'uint16');
  127. fwrite(FileID,NEV.MetaTags.HeaderOffset,'uint32');
  128. fwrite(FileID,NEV.MetaTags.PacketBytes,'uint32');
  129. fwrite(FileID,NEV.MetaTags.SampleRes,'uint32');
  130. fwrite(FileID,NEV.MetaTags.TimeRes,'uint32');
  131. fwrite(FileID,NEV.MetaTags.DateTimeRaw,'uint16');
  132. fwrite(FileID,'saveNEV$version1001$$$$$$$$$$$$$');
  133. fwrite(FileID,NEV.MetaTags.Comment);
  134. ExtendedHeaderBytes = NEV.MetaTags.HeaderOffset-ftell(FileID)+4;
  135. fwrite(FileID,ExtendedHeaderBytes/32,'uint32');
  136. EndOfBasicHeader = ftell(FileID);
  137. %%
  138. % Write the extended header into the file.
  139. %Handling packets with array information
  140. if isfield(NEV,'ArrayInfo')
  141. if reportFlag; disp('Writing Array Header...'); end
  142. if isfield(NEV.ArrayInfo,'ElectrodeName')
  143. fwrite(FileID,'ARRAYNME');
  144. fwrite(FileID,NEV.ArrayInfo.ElectrodeName); %Must null terminate
  145. end
  146. if isfield(NEV.ArrayInfo,'ArrayComment')
  147. fwrite(FileID,'ECOMMENT');
  148. fwrite(FileID,NEV.ArrayInfo.ArrayComment); %Must null terminate
  149. end
  150. if isfield(NEV.ArrayInfo,'ArrayCommentCont')
  151. fwrite(FileID,'CCOMMENT');
  152. fwrite(FileID,NEV.ArrayInfo.ArrayCommentCont); %Must null terminate
  153. end
  154. if isfield(NEV.ArrayInfo,'MapFile')
  155. fwrite(FileID,'MAPFILE'); %+NULL
  156. fwrite(FileID,NEV.ArrayInfo.MapFile); %Must null terminate
  157. end
  158. end
  159. if isfield(NEV,'ElectrodesInfo')
  160. if reportFlag; disp('Writing Electrode Header...'); end
  161. if (isfield(NEV.ElectrodesInfo(1),'ElectrodeID'))
  162. %Find length of electrode count, loop through for that count and fill
  163. %in NEUEVWAV packets.
  164. for IDX = 1:length(NEV.ElectrodesInfo)
  165. Before = ftell(FileID);
  166. fwrite(FileID,'NEUEVWAV');
  167. fwrite(FileID,NEV.ElectrodesInfo(IDX).ElectrodeID,'uint16');
  168. %fwrite(FileID,NEV.ElectrodesInfo(IDX).ConnectorBank);
  169. switch NEV.ElectrodesInfo(IDX).ConnectorBank
  170. case 'A'
  171. fwrite(FileID,1,'uint8');
  172. case 'B'
  173. fwrite(FileID,2,'uint8');
  174. case 'C'
  175. fwrite(FileID,3,'uint8');
  176. case 'D'
  177. fwrite(FileID,4,'uint8');
  178. case 'E'
  179. fwrite(FileID,5,'uint8');
  180. case 'F'
  181. fwrite(FileID,6,'uint8');
  182. case 'G'
  183. fwrite(FileID,7,'uint8');
  184. case 'H'
  185. fwrite(FileID,8,'uint8');
  186. case 'I'
  187. fwrite(FileID,9,'uint8');
  188. end
  189. fwrite(FileID,NEV.ElectrodesInfo(IDX).ConnectorPin,'uint8');
  190. fwrite(FileID,NEV.ElectrodesInfo(IDX).DigitalFactor,'uint16');
  191. fwrite(FileID,NEV.ElectrodesInfo(IDX).EnergyThreshold,'uint16');
  192. fwrite(FileID,NEV.ElectrodesInfo(IDX).HighThreshold,'int16');
  193. fwrite(FileID,NEV.ElectrodesInfo(IDX).LowThreshold,'int16');
  194. fwrite(FileID,NEV.ElectrodesInfo(IDX).Units,'uint8');
  195. fwrite(FileID,NEV.ElectrodesInfo(IDX).WaveformBytes,'uint8');
  196. if isempty(NEV.Data.Spikes.Waveform)
  197. fwrite(FileID,48,'uint16');
  198. SpikeLength = 48;
  199. else
  200. fwrite(FileID,length(NEV.Data.Spikes.Waveform(:,1)),'uint16');
  201. SpikeLength = length(NEV.Data.Spikes.Waveform(:,1));
  202. end
  203. %if file type is 2.2, don't need previous field and end in 10
  204. %zeros
  205. fwrite(FileID,zeros(8,1),'uint8');
  206. After = ftell(FileID);
  207. if After-Before ~= 32
  208. disp('Broken Electrode Info')
  209. NEV.ElectrodesInfo(IDX).ConnectorBank
  210. end
  211. end
  212. end
  213. if (isfield(NEV.ElectrodesInfo(1),'ElectrodeLabel'))
  214. for IDX = 1:length(NEV.ElectrodesInfo)
  215. Before = ftell(FileID);
  216. fwrite(FileID,'NEUEVLBL');
  217. fwrite(FileID, NEV.ElectrodesInfo(IDX).ElectrodeID,'uint16');
  218. fwrite(FileID, NEV.ElectrodesInfo(IDX).ElectrodeLabel);%Must be nulll terminated
  219. fwrite(FileID, zeros(6,1),'uint8');
  220. After = ftell(FileID);
  221. if After-Before ~= 32
  222. disp('Broken Electrode Label')
  223. end
  224. end
  225. end
  226. if (isfield(NEV.ElectrodesInfo(1),'HighFreqCorner'))
  227. for IDX = 1:length(NEV.ElectrodesInfo)
  228. Before = ftell(FileID);
  229. fwrite(FileID,'NEUEVFLT');
  230. fwrite(FileID, NEV.ElectrodesInfo(IDX).ElectrodeID,'uint16');
  231. fwrite(FileID, NEV.ElectrodesInfo(IDX).HighFreqCorner,'uint32');
  232. fwrite(FileID, NEV.ElectrodesInfo(IDX).HighFreqOrder,'uint32');
  233. fwrite(FileID, NEV.ElectrodesInfo(IDX).HighFilterType,'uint16');
  234. fwrite(FileID, NEV.ElectrodesInfo(IDX).LowFreqCorner,'uint32');
  235. fwrite(FileID, NEV.ElectrodesInfo(IDX).LowFreqOrder,'uint32');
  236. fwrite(FileID, NEV.ElectrodesInfo(IDX).LowFilterType,'uint16');
  237. fwrite(FileID, zeros(2,1), 'uint8');
  238. After = ftell(FileID);
  239. if After-Before ~= 32
  240. disp('Broken High Freq Corner');
  241. end
  242. end
  243. end
  244. end
  245. %Digital inputs
  246. if isfield(NEV,'IOLabels')
  247. if reportFlag; disp('Writing IOLabels Header...'); end
  248. for IDX = 1:length(NEV.IOLabels)
  249. Before = ftell(FileID);
  250. fwrite(FileID,'DIGLABEL');
  251. fwrite(FileID,'Serial1XXXXXXXXX','uint8');
  252. fwrite(FileID, IDX - 1, 'uint8');
  253. fwrite(FileID, zeros(7,1),'uint8');
  254. After = ftell(FileID);
  255. if After-Before ~= 32
  256. disp('Broken IO Labels');
  257. end
  258. end
  259. end
  260. %Video Packets
  261. if isfield(NEV,'VideoSyncInfo')
  262. if reportFlag; disp('Writing Video Header...'); end
  263. for IDX = 1:length(NEV.VideoSyncInfo)
  264. Before = ftell(FileID);
  265. fwrite(FileID,'VIDEOSYN');
  266. fwrite(FileID, NEV.VideoSyncInfo(IDX).SourceID, 'uint16');
  267. fwrite(FileID, NEV.VideoSyncInfo(IDX).SourceName(1:16));
  268. fwrite(FileID, NEV.VideoSyncInfo(IDX).FrameRateFPS,'single');
  269. fwrite(FileID, zeros(2,1),'uint8');
  270. After = ftell(FileID);
  271. if After-Before ~= 32
  272. disp('Broken Video Sync Info');
  273. PacketNumber = IDX;
  274. TotalPackets = length(NEV.VideoSyncInfo);
  275. end
  276. end
  277. end
  278. if isfield(NEV,'NSAS')
  279. %This might exist in a future version of Central
  280. end
  281. if isfield(NEV,'ObjTrackInfo')
  282. if reportFlag; disp('Writing Tracking Header...'); end
  283. for IDX = 1:length(NEV.ObjTrackInfo)
  284. Before = ftell(FileID);
  285. fwrite(FileID,'TRACKOBJ');
  286. fwrite(FileID, NEV.ObjTrackInfo(IDX).TrackableType,'uint16');
  287. fwrite(FileID, NEV.ObjTrackInfo(IDX).TrackableID,'uint32');%This is an error and should be two different uint16 values, but we can read it back into file this way.
  288. NEV.ObjTrackInfo(IDX).TrackableName = pad(NEV.ObjTrackInfo(IDX).TrackableName,16,'X');
  289. fwrite(FileID, NEV.ObjTrackInfo(IDX).TrackableName);
  290. fwrite(FileID, zeros(2,1),'uint8');
  291. After = ftell(FileID);
  292. if After-Before ~= 32
  293. disp('Broken Obj Track Info');
  294. end
  295. end
  296. end
  297. if isfield(NEV,'Rabbits')
  298. %Fill in the details about Rabbits at some point in the future.
  299. end
  300. EndOfExtendedHeader = ftell(FileID);
  301. %% Edit the Basic Header to Account for Number of Extended Headers
  302. fseek(FileID,12,'bof');
  303. fwrite(FileID,EndOfExtendedHeader,'uint32');
  304. fseek(FileID,322,'bof');
  305. fwrite(FileID,(EndOfExtendedHeader-EndOfBasicHeader)/32,'uint32');
  306. fseek(FileID,EndOfExtendedHeader,'bof');
  307. %%
  308. % Write Data
  309. BytesInPackets = NEV.MetaTags.PacketBytes;
  310. Broken = 0;
  311. %SerialDigitalIO CHECK
  312. if ~isempty(NEV.Data.SerialDigitalIO.TimeStamp)
  313. if reportFlag; disp('Writing Serial/Digital Data...'); end
  314. for IDX = 1:length(NEV.Data.SerialDigitalIO.TimeStamp)
  315. Before = ftell(FileID);
  316. fwrite(FileID, NEV.Data.SerialDigitalIO.TimeStamp(IDX),'uint32');
  317. %ftell(FileID)-Before
  318. fwrite(FileID, 0,'uint16');
  319. %ftell(FileID)-Before
  320. fwrite(FileID, NEV.Data.SerialDigitalIO.InsertionReason(IDX));
  321. %ftell(FileID)-Before
  322. fwrite(FileID, '0');
  323. %ftell(FileID)-Before
  324. if ~isempty(NEV.Data.SerialDigitalIO.Value)
  325. fwrite(FileID, NEV.Data.SerialDigitalIO.Value(IDX),'uint16');
  326. else
  327. fwrite(FileID, NEV.Data.SerialDigitalIO.UnparsedData(IDX),'uint16');
  328. end
  329. %ftell(FileID)-Before
  330. fwrite(FileID, zeros(BytesInPackets-10,1),'uint8');
  331. %ftell(FileID)-Before
  332. After = ftell(FileID);
  333. if After-Before ~= BytesInPackets
  334. Broken = 1;
  335. %After-Before
  336. %CurrentPacket = IDX
  337. %TotalPackets = length(NEV.Data.SerialDigitalIO.TimeStamp)
  338. end
  339. end
  340. if Broken == 1
  341. disp('Serial Digital Packet Corrupted');
  342. Broken = 0;
  343. end
  344. end
  345. %Spikes CHECK
  346. if ~isempty(NEV.Data.Spikes.TimeStamp)
  347. if reportFlag; disp('Writing Spike Data...'); end
  348. for IDX = 1:length(NEV.Data.Spikes.TimeStamp)
  349. Before = ftell(FileID);
  350. fwrite(FileID, NEV.Data.Spikes.TimeStamp(IDX),'uint32');
  351. fwrite(FileID, NEV.Data.Spikes.Electrode(IDX),'uint16');
  352. fwrite(FileID, NEV.Data.Spikes.Unit(IDX),'uchar');
  353. fwrite(FileID, 0,'uchar');
  354. fwrite(FileID, NEV.Data.Spikes.Waveform(:,IDX)','int16');
  355. %for Value = 1:SpikeLength
  356. % fwrite(FileID, NEV.Data.Spikes.Waveform(Value,IDX),'int16');
  357. %end
  358. After = ftell(FileID);
  359. if After-Before ~= BytesInPackets
  360. Broken = 1;
  361. end
  362. end
  363. if Broken == 1
  364. disp('Spike Packet Corrupted')
  365. Broken = 0;
  366. end
  367. end
  368. %disp('done')
  369. %Comments CHECK
  370. if ~isempty(NEV.Data.Comments.TimeStamp)
  371. if reportFlag; disp('Writing Comment Data...'); end
  372. for IDX = 1:length(NEV.Data.Comments.TimeStamp)
  373. Before = ftell(FileID);
  374. fwrite(FileID, NEV.Data.Comments.TimeStamp(IDX),'uint32');
  375. %ftell(FileID)-Before
  376. fwrite(FileID, 65535, 'uint16');
  377. %ftell(FileID)-Before
  378. fwrite(FileID, NEV.Data.Comments.CharSet(IDX),'uint8');
  379. %ftell(FileID)-Before
  380. fwrite(FileID, 0,'uint8');
  381. %ftell(FileID)-Before
  382. fwrite(FileID, NEV.Data.Comments.Color(IDX),'uint32');
  383. %ftell(FileID)-Before
  384. fwrite(FileID, NEV.Data.Comments.Text(IDX,:));
  385. %ftell(FileID)-Before
  386. %Need to handle extra characters here etc
  387. fwrite(FileID, zeros(BytesInPackets-(ftell(FileID)-Before),1),'uint8');
  388. After = ftell(FileID);
  389. if After-Before ~= BytesInPackets
  390. Broken = 1;
  391. %After-Before
  392. %CurrentPacket = IDX
  393. %TotalPackets = length(NEV.Data.Comments.TimeStamp)
  394. end
  395. end
  396. if Broken == 1
  397. disp('Comment Packet Corrupted')
  398. Broken = 0;
  399. end
  400. end
  401. if ~isempty(NEV.Data.TrackingEvents.TimeStamp)
  402. if reportFlag; disp('Writing Tracking Event Data'); end
  403. for IDX = 1:length(NEV.Data.TrackingEvents.TimeStamp)
  404. Before = ftell(FileID);
  405. fwrite(FileID, NEV.Data.TrackingEvents.TimeStamp(IDX),'uint32');
  406. fwrite(FileID, 65535,'uint16');
  407. fwrite(FileID, 255, 'uint8');
  408. %fwrite(FileID, 2, 'uint8');
  409. fwrite(FileID, 0, 'uint8'); %placeholder until I ask hyrum what the Nreuromotive flag is
  410. fwrite(FileID, int2str(NEV.Data.TrackingEvents.ROINum(IDX)),'uint8');
  411. %byte 1 is ROI #, byte 2 is enter or exit -- is it 1 and 2?
  412. if strcmp(NEV.Data.TrackingEvents.Event(IDX),'Enter')
  413. fwrite(FileID, 1,'uint8');
  414. elseif strcmp(NEV.Data.TrackingEvents.Event(IDX),'Exit')
  415. fwrite(FileID, 2,'uint8');
  416. end
  417. fwrite(FileID, zeros(2,1), 'uint8');
  418. fwrite(FileID, strcat(NEV.Data.TrackingEvents.ROIName{IDX},':',int2str(NEV.Data.TrackingEvents.ROINum(IDX)),':',NEV.Data.TrackingEvents.Event{IDX},':',int2str(NEV.Data.TrackingEvents.Frame(IDX)),':','placeholder until i figure out wtf this is'));
  419. fwrite(FileID, zeros(BytesInPackets-(ftell(FileID)-Before),1),'uint8');
  420. After = ftell(FileID);
  421. if After-Before ~= BytesInPackets
  422. Broken = 1;
  423. %After-Before
  424. %CurrentPacket = IDX
  425. %TotalPackets = length(NEV.Data.Comments.TimeStamp)
  426. end
  427. end
  428. if Broken == 1
  429. disp('Tracking Event Packet Corrupted')
  430. Broken = 0;
  431. end
  432. end
  433. if ~isempty(NEV.Data.VideoSync.TimeStamp)
  434. if reportFlag; disp('Writing VideoSync Data...'); end
  435. for IDX = 1:length(NEV.Data.VideoSync.TimeStamp)
  436. Before = ftell(FileID);
  437. fwrite(FileID, NEV.Data.VideoSync.TimeStamp(IDX),'uint32');
  438. %ftell(FileID)-Before
  439. fwrite(FileID, 65534, 'uint16');
  440. %ftell(FileID)-Before
  441. fwrite(FileID, NEV.Data.VideoSync.FileNumber(IDX),'uint16');
  442. %ftell(FileID)-Before
  443. fwrite(FileID, NEV.Data.VideoSync.FrameNumber(IDX),'uint32');%Wrong Size
  444. %ftell(FileID)-Before
  445. fwrite(FileID, NEV.Data.VideoSync.ElapsedTime(IDX),'uint32');%Wrong Size
  446. %ftell(FileID)-Before
  447. fwrite(FileID, NEV.Data.VideoSync.SourceID(IDX),'uint32');
  448. %ftell(FileID)-Before
  449. fwrite(FileID, zeros(BytesInPackets - 20,1),'uint8');
  450. %ftell(FileID)-Before
  451. After = ftell(FileID);
  452. if After-Before ~= BytesInPackets
  453. Broken = 1;
  454. %After-Before
  455. %CurrentPacket = IDX
  456. %TotalPackets = length(NEV.Data.VideoSync.TimeStamp)
  457. end
  458. end
  459. if Broken == 1
  460. disp('Video Sync Packet Corrupted')
  461. Broken = 0;
  462. end
  463. end
  464. if ~isempty(NEV.Data.Tracking)
  465. if reportFlag; disp('Writing Tracking Data...'); end
  466. TrackingFieldNames = fieldnames(NEV.Data.Tracking);
  467. for TrackingField = 1:numel(TrackingFieldNames)
  468. for IDX = 1:length(NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).TimeStamp)
  469. Before = ftell(FileID);
  470. if NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCount == 0
  471. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).TimeStamp(IDX),'uint32');
  472. %ftell(FileID)-Before
  473. fwrite(FileID, 65533, 'uint16');
  474. %ftell(FileID)-Before
  475. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).ParentID(IDX),'uint16');
  476. %ftell(FileID)-Before
  477. fwrite(FileID, TrackingField-1,'uint16'); %Node ID
  478. %ftell(FileID)-Before
  479. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).NodeCount(IDX),'uint16');
  480. %ftell(FileID)-Before
  481. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCount(IDX),'uint16');
  482. %ftell(FileID)-Before
  483. fwrite(FileID, zeros(2,1),'uint8');
  484. %ftell(FileID)-Before
  485. fwrite(FileID, zeros(BytesInPackets - 16,1),'uint8');
  486. else
  487. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).TimeStamp(IDX),'uint32');
  488. %ftell(FileID)-Before
  489. fwrite(FileID, 65533, 'uint16');
  490. %ftell(FileID)-Before
  491. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).ParentID(IDX),'uint16');
  492. %ftell(FileID)-Before
  493. fwrite(FileID, TrackingField-1,'uint16'); %Node ID
  494. %ftell(FileID)-Before
  495. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).NodeCount(IDX),'uint16');
  496. %ftell(FileID)-Before
  497. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCount(IDX),'uint16');
  498. %ftell(FileID)-Before
  499. MarkerCoordinatesBytes = length(NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCoordinates(IDX).X);
  500. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCoordinates(IDX).X,'uint16');
  501. %ftell(FileID)-Before
  502. fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCoordinates(IDX).Y,'uint16');
  503. %ftell(FileID)-Before
  504. if MarkerCoordinatesBytes == 1
  505. fwrite(FileID, zeros(BytesInPackets - 14-MarkerCoordinatesBytes*4,1),'uint8');
  506. else
  507. fwrite(FileID, zeros(BytesInPackets - 14-MarkerCoordinatesBytes*4,1),'uint8');
  508. end
  509. end
  510. After = ftell(FileID);
  511. if After-Before ~= BytesInPackets
  512. Broken = 1;
  513. %After-Before
  514. %CurrentPacket = IDX
  515. %TotalPackets = length(NEV.Data.VideoSync.TimeStamp)
  516. end
  517. %Must somehow terminate in correct number of zeros
  518. end
  519. if Broken == 1
  520. disp('Tracking Packet Corrupted')
  521. disp(After - Before)
  522. Broken = 0;
  523. end
  524. end
  525. end
  526. if ~isempty(NEV.Data.PatientTrigger.TimeStamp)
  527. if reportFlag; disp('Writing Patient Trigger Data...'); end
  528. for IDX = 1:length(NEV.Data.PatientTrigger.TimeStamp)
  529. Before = ftell(FileID);
  530. fwrite(FileID, NEV.Data.PatientTrigger.TimeStamp(IDX),'uint32');
  531. %ftell(FileID)-Before
  532. fwrite(FileID, 65532, 'uint16');
  533. %ftell(FileID)-Before
  534. fwrite(FileID, NEV.Data.PatientTrigger.TriggerType(IDX),'uint16');
  535. %ftell(FileID)-Before
  536. fwrite(FileID, zeros(BytesInPackets - 8, 1),'uint8');
  537. %ftell(FileID)-Before
  538. After = ftell(FileID);
  539. if After-Before ~= BytesInPackets
  540. Broken = 1;
  541. %After-Before
  542. %CurrentPacket = IDX
  543. %TotalPackets = length(NEV.Data.PatientTrigger.TimeStamp)
  544. end
  545. end
  546. if Broken == 1
  547. disp('Patient Trigger Packet Corrupted')
  548. Broken = 0;
  549. end
  550. end
  551. if ~isempty(NEV.Data.Reconfig.TimeStamp)
  552. if reportFlag; disp('Writing Reconfig Data...'); end
  553. for IDX = 1:length(NEV.Data.Reconfig.TimeStamp)
  554. Before = ftell(FileID);
  555. fwrite(FileID, NEV.Data.Reconfig.TimeStamp(IDX),'uint32');
  556. %ftell(FileID)-Before
  557. fwrite(FileID, 65531, 'uint16');
  558. %ftell(FileID)-Before
  559. fwrite(FileID, NEV.Data.Reconfig.ChangeType(IDX),'uint16');
  560. %ftell(FileID)-Before
  561. fwrite(FileID, zeros(BytesInPackets - 8,1),'uint8');
  562. %ftell(FileID)-Before
  563. After = ftell(FileID);
  564. if After-Before ~= BytesInPackets
  565. Broken = 1;
  566. %After-Before
  567. %CurrentPacket = IDX
  568. %TotalPackets = length(NEV.Data.Reconfig.TimeStamp)
  569. end
  570. end
  571. if Broken == 1
  572. disp('Reconfig Packet Corrupted')
  573. Broken = 0;
  574. end
  575. end
  576. if reportFlag; disp('Finished!'); end
  577. clear After
  578. clear Before
  579. clear Broken
  580. clear BytesInPackeets
  581. clear ExtendedHederBytes
  582. clear FilePath
  583. clear IDX
  584. clear SpikeLength
  585. clear Value
  586. fclose('all');