Prechádzať zdrojové kódy

Welcome to the V1-V4 resting state data repository

Aitor Morales-Gregorio a.morales-gregorio@fz-juelich.de 2 rokov pred
commit
51445b6649
100 zmenil súbory, kde vykonal 11439 pridanie a 0 odobranie
  1. 321 0
      LICENSE
  2. 198 0
      README.md
  3. 11 0
      code/LICENSE
  4. 10 0
      code/README.md
  5. 11 0
      code/matlab_scripts/NPMK/@KTFigure/.svn/all-wcprops
  6. 62 0
      code/matlab_scripts/NPMK/@KTFigure/.svn/entries
  7. 48 0
      code/matlab_scripts/NPMK/@KTFigure/.svn/text-base/KTFigure.m.svn-base
  8. 48 0
      code/matlab_scripts/NPMK/@KTFigure/KTFigure.m
  9. 11 0
      code/matlab_scripts/NPMK/@KTFigureAxis/.svn/all-wcprops
  10. 62 0
      code/matlab_scripts/NPMK/@KTFigureAxis/.svn/entries
  11. 79 0
      code/matlab_scripts/NPMK/@KTFigureAxis/.svn/text-base/KTFigureAxis.m.svn-base
  12. 79 0
      code/matlab_scripts/NPMK/@KTFigureAxis/KTFigureAxis.m
  13. 131 0
      code/matlab_scripts/NPMK/@KTNEVComments/KTNEVComments.m
  14. 11 0
      code/matlab_scripts/NPMK/@KTNSPOnline/.svn/all-wcprops
  15. 62 0
      code/matlab_scripts/NPMK/@KTNSPOnline/.svn/entries
  16. 470 0
      code/matlab_scripts/NPMK/@KTNSPOnline/.svn/text-base/KTNSPOnline.m.svn-base
  17. 470 0
      code/matlab_scripts/NPMK/@KTNSPOnline/KTNSPOnline.m
  18. 11 0
      code/matlab_scripts/NPMK/@KTUEAImpedanceFile/.svn/all-wcprops
  19. 62 0
      code/matlab_scripts/NPMK/@KTUEAImpedanceFile/.svn/entries
  20. 249 0
      code/matlab_scripts/NPMK/@KTUEAImpedanceFile/.svn/text-base/KTUEAImpedanceFile.m.svn-base
  21. 249 0
      code/matlab_scripts/NPMK/@KTUEAImpedanceFile/KTUEAImpedanceFile.m
  22. 11 0
      code/matlab_scripts/NPMK/@KTUEAMapFile/.svn/all-wcprops
  23. 62 0
      code/matlab_scripts/NPMK/@KTUEAMapFile/.svn/entries
  24. 256 0
      code/matlab_scripts/NPMK/@KTUEAMapFile/.svn/text-base/KTUEAMapFile.m.svn-base
  25. 277 0
      code/matlab_scripts/NPMK/@KTUEAMapFile/KTUEAMapFile.m
  26. BIN
      code/matlab_scripts/NPMK/Dependent Functions/.DS_Store
  27. 35 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/all-wcprops
  28. 222 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/entries
  29. 68 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/getFile.m.svn-base
  30. 39 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/getFolder.m.svn-base
  31. 11 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/getSettingFileFullPath.m.svn-base
  32. 56 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/parseCommand.m.svn-base
  33. 115 0
      code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/sortNEV.m.svn-base
  34. BIN
      code/matlab_scripts/NPMK/Dependent Functions/bnsx.dat
  35. 85 0
      code/matlab_scripts/NPMK/Dependent Functions/getFile.m
  36. 39 0
      code/matlab_scripts/NPMK/Dependent Functions/getFolder.m
  37. 15 0
      code/matlab_scripts/NPMK/Dependent Functions/getSettingFileFullPath.m
  38. 148 0
      code/matlab_scripts/NPMK/Dependent Functions/parseCCF.m
  39. 56 0
      code/matlab_scripts/NPMK/Dependent Functions/parseCommand.m
  40. 64 0
      code/matlab_scripts/NPMK/Dependent Functions/syncPatternDetectNEV.m
  41. 67 0
      code/matlab_scripts/NPMK/Dependent Functions/syncPatternDetectNSx.m
  42. 73 0
      code/matlab_scripts/NPMK/Dependent Functions/syncPatternFinderNSx.m
  43. 5 0
      code/matlab_scripts/NPMK/LoadingEngines/.svn/all-wcprops
  44. 31 0
      code/matlab_scripts/NPMK/LoadingEngines/.svn/entries
  45. BIN
      code/matlab_scripts/NPMK/LoadingEngines/MClust/.DS_Store
  46. 11 0
      code/matlab_scripts/NPMK/LoadingEngines/MClust/.svn/all-wcprops
  47. 62 0
      code/matlab_scripts/NPMK/LoadingEngines/MClust/.svn/entries
  48. 144 0
      code/matlab_scripts/NPMK/LoadingEngines/MClust/.svn/text-base/BlackrockNEVLoadingEngine.m.svn-base
  49. 193 0
      code/matlab_scripts/NPMK/LoadingEngines/MClust/BlackrockNEVLoadingEngine.m
  50. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Linux/nsNEVLibrary.so
  51. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/msvcp71.dll
  52. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/msvcr71.dll
  53. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/nsNEVLibrary.dll
  54. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/nsNEVLibrary64.dll
  55. 700 0
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/ns/ns.c
  56. 776 0
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/ns/ns.h
  57. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/Nex Setup.jpg
  58. BIN
      code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/OFS Setup.jpg
  59. BIN
      code/matlab_scripts/NPMK/NEV Utilities/.DS_Store
  60. 91 0
      code/matlab_scripts/NPMK/NEV Utilities/findEventTimes.m
  61. 76 0
      code/matlab_scripts/NPMK/NEV Utilities/mergeNEV.m
  62. 819 0
      code/matlab_scripts/NPMK/NEV Utilities/openNEVTracking.m
  63. 646 0
      code/matlab_scripts/NPMK/NEV Utilities/saveNEV.m
  64. 137 0
      code/matlab_scripts/NPMK/NEV Utilities/saveNEVSpikes.m
  65. 129 0
      code/matlab_scripts/NPMK/NEV Utilities/saveNEVSubSpikes.m
  66. 115 0
      code/matlab_scripts/NPMK/NEV Utilities/sortNEV.m
  67. 95 0
      code/matlab_scripts/NPMK/NEV Utilities/splitNEVResets.m
  68. BIN
      code/matlab_scripts/NPMK/NPMKverChecker.dat
  69. 66 0
      code/matlab_scripts/NPMK/NPMKverChecker.m
  70. BIN
      code/matlab_scripts/NPMK/NSx Utilities/.DS_Store
  71. 21 0
      code/matlab_scripts/NPMK/NSx Utilities/NSxPowerSpectrum.m
  72. 88 0
      code/matlab_scripts/NPMK/NSx Utilities/NSxToHL.m
  73. 38 0
      code/matlab_scripts/NPMK/NSx Utilities/calcTimeDelay.m
  74. 114 0
      code/matlab_scripts/NPMK/NSx Utilities/combineNSxNEV.m
  75. 168 0
      code/matlab_scripts/NPMK/NSx Utilities/findSpikes.m
  76. 148 0
      code/matlab_scripts/NPMK/NSx Utilities/matrixToNSx.m
  77. 233 0
      code/matlab_scripts/NPMK/NSx Utilities/mergeNSxNEV.m
  78. 60 0
      code/matlab_scripts/NPMK/NSx Utilities/mergeNSxNEVSeries.m
  79. 118 0
      code/matlab_scripts/NPMK/NSx Utilities/openNSxHL.m
  80. 115 0
      code/matlab_scripts/NPMK/NSx Utilities/plotAverageWaveforms.m
  81. 93 0
      code/matlab_scripts/NPMK/NSx Utilities/removeNSxData.m
  82. 150 0
      code/matlab_scripts/NPMK/NSx Utilities/rethresholdNSx.m
  83. 223 0
      code/matlab_scripts/NPMK/NSx Utilities/saveChNSx.m
  84. 381 0
      code/matlab_scripts/NPMK/NSx Utilities/saveNSx.m
  85. 8 0
      code/matlab_scripts/NPMK/NSx Utilities/separatePausedNSx.m
  86. 89 0
      code/matlab_scripts/NPMK/NSx Utilities/separatePausedNSx_old.m
  87. 126 0
      code/matlab_scripts/NPMK/NSx Utilities/splitNSx.m
  88. 133 0
      code/matlab_scripts/NPMK/NSx Utilities/splitNSxPauses.m
  89. BIN
      code/matlab_scripts/NPMK/NTrode Utilities/.DS_Store
  90. 28 0
      code/matlab_scripts/NPMK/NTrode Utilities/ntrodeGroups.m
  91. 80 0
      code/matlab_scripts/NPMK/NTrode Utilities/saveNEVTetrodes.m
  92. 68 0
      code/matlab_scripts/NPMK/NTrode Utilities/splitNEVNTrode.m
  93. 139 0
      code/matlab_scripts/NPMK/NTrode Utilities/splitNSxNTrode.m
  94. 23 0
      code/matlab_scripts/NPMK/Other tools/.svn/all-wcprops
  95. 130 0
      code/matlab_scripts/NPMK/Other tools/.svn/entries
  96. 21 0
      code/matlab_scripts/NPMK/Other tools/.svn/text-base/kshuffle.m.svn-base
  97. 16 0
      code/matlab_scripts/NPMK/Other tools/.svn/text-base/offline2Struct.m.svn-base
  98. 94 0
      code/matlab_scripts/NPMK/Other tools/.svn/text-base/playSound.m.svn-base
  99. 84 0
      code/matlab_scripts/NPMK/Other tools/edgeDetect.m
  100. 0 0
      code/matlab_scripts/NPMK/Other tools/kshuffle.m

+ 321 - 0
LICENSE

@@ -0,0 +1,321 @@
+V1_V4_1024_electrode_resting_state_data (c) by Xing Chen, Aitor Morales-Gregorio, Julia Sprenger, Alexander Kleinjohann, Shashwat Sridhar, Sacha J. van Albada, Sonja Grün and Pieter R. Roelfsema
+
+V1_V4_1024_electrode_resting_state_data is licensed under a
+
+Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+  a. Adapted Material means material subject to Copyright and Similar
+     Rights that is derived from or based upon the Licensed Material
+     and in which the Licensed Material is translated, altered,
+     arranged, transformed, or otherwise modified in a manner requiring
+     permission under the Copyright and Similar Rights held by the
+     Licensor. For purposes of this Public License, where the Licensed
+     Material is a musical work, performance, or sound recording,
+     Adapted Material is always produced where the Licensed Material is
+     synched in timed relation with a moving image.
+
+  b. Adapter's License means the license You apply to Your Copyright
+     and Similar Rights in Your contributions to Adapted Material in
+     accordance with the terms and conditions of this Public License.
+
+  c. Copyright and Similar Rights means copyright and/or similar rights
+     closely related to copyright including, without limitation,
+     performance, broadcast, sound recording, and Sui Generis Database
+     Rights, without regard to how the rights are labeled or
+     categorized. For purposes of this Public License, the rights
+     specified in Section 2(b)(1)-(2) are not Copyright and Similar
+     Rights.
+
+  d. Effective Technological Measures means those measures that, in the
+     absence of proper authority, may not be circumvented under laws
+     fulfilling obligations under Article 11 of the WIPO Copyright
+     Treaty adopted on December 20, 1996, and/or similar international
+     agreements.
+
+  e. Exceptions and Limitations means fair use, fair dealing, and/or
+     any other exception or limitation to Copyright and Similar Rights
+     that applies to Your use of the Licensed Material.
+
+  f. Licensed Material means the artistic or literary work, database,
+     or other material to which the Licensor applied this Public
+     License.
+
+  g. Licensed Rights means the rights granted to You subject to the
+     terms and conditions of this Public License, which are limited to
+     all Copyright and Similar Rights that apply to Your use of the
+     Licensed Material and that the Licensor has authority to license.
+
+  h. Licensor means the individual(s) or entity(ies) granting rights
+     under this Public License.
+
+  i. Share means to provide material to the public by any means or
+     process that requires permission under the Licensed Rights, such
+     as reproduction, public display, public performance, distribution,
+     dissemination, communication, or importation, and to make material
+     available to the public including in ways that members of the
+     public may access the material from a place and at a time
+     individually chosen by them.
+
+  j. Sui Generis Database Rights means rights other than copyright
+     resulting from Directive 96/9/EC of the European Parliament and of
+     the Council of 11 March 1996 on the legal protection of databases,
+     as amended and/or succeeded, as well as other essentially
+     equivalent rights anywhere in the world.
+
+  k. You means the individual or entity exercising the Licensed Rights
+     under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+  a. License grant.
+
+       1. Subject to the terms and conditions of this Public License,
+          the Licensor hereby grants You a worldwide, royalty-free,
+          non-sublicensable, non-exclusive, irrevocable license to
+          exercise the Licensed Rights in the Licensed Material to:
+
+            a. reproduce and Share the Licensed Material, in whole or
+               in part; and
+
+            b. produce, reproduce, and Share Adapted Material.
+
+       2. Exceptions and Limitations. For the avoidance of doubt, where
+          Exceptions and Limitations apply to Your use, this Public
+          License does not apply, and You do not need to comply with
+          its terms and conditions.
+
+       3. Term. The term of this Public License is specified in Section
+          6(a).
+
+       4. Media and formats; technical modifications allowed. The
+          Licensor authorizes You to exercise the Licensed Rights in
+          all media and formats whether now known or hereafter created,
+          and to make technical modifications necessary to do so. The
+          Licensor waives and/or agrees not to assert any right or
+          authority to forbid You from making technical modifications
+          necessary to exercise the Licensed Rights, including
+          technical modifications necessary to circumvent Effective
+          Technological Measures. For purposes of this Public License,
+          simply making modifications authorized by this Section 2(a)
+          (4) never produces Adapted Material.
+
+       5. Downstream recipients.
+
+            a. Offer from the Licensor -- Licensed Material. Every
+               recipient of the Licensed Material automatically
+               receives an offer from the Licensor to exercise the
+               Licensed Rights under the terms and conditions of this
+               Public License.
+
+            b. No downstream restrictions. You may not offer or impose
+               any additional or different terms or conditions on, or
+               apply any Effective Technological Measures to, the
+               Licensed Material if doing so restricts exercise of the
+               Licensed Rights by any recipient of the Licensed
+               Material.
+
+       6. No endorsement. Nothing in this Public License constitutes or
+          may be construed as permission to assert or imply that You
+          are, or that Your use of the Licensed Material is, connected
+          with, or sponsored, endorsed, or granted official status by,
+          the Licensor or others designated to receive attribution as
+          provided in Section 3(a)(1)(A)(i).
+
+  b. Other rights.
+
+       1. Moral rights, such as the right of integrity, are not
+          licensed under this Public License, nor are publicity,
+          privacy, and/or other similar personality rights; however, to
+          the extent possible, the Licensor waives and/or agrees not to
+          assert any such rights held by the Licensor to the limited
+          extent necessary to allow You to exercise the Licensed
+          Rights, but not otherwise.
+
+       2. Patent and trademark rights are not licensed under this
+          Public License.
+
+       3. To the extent possible, the Licensor waives any right to
+          collect royalties from You for the exercise of the Licensed
+          Rights, whether directly or through a collecting society
+          under any voluntary or waivable statutory or compulsory
+          licensing scheme. In all other cases the Licensor expressly
+          reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+  a. Attribution.
+
+       1. If You Share the Licensed Material (including in modified
+          form), You must:
+
+            a. retain the following if it is supplied by the Licensor
+               with the Licensed Material:
+
+                 i. identification of the creator(s) of the Licensed
+                    Material and any others designated to receive
+                    attribution, in any reasonable manner requested by
+                    the Licensor (including by pseudonym if
+                    designated);
+
+                ii. a copyright notice;
+
+               iii. a notice that refers to this Public License;
+
+                iv. a notice that refers to the disclaimer of
+                    warranties;
+
+                 v. a URI or hyperlink to the Licensed Material to the
+                    extent reasonably practicable;
+
+            b. indicate if You modified the Licensed Material and
+               retain an indication of any previous modifications; and
+
+            c. indicate the Licensed Material is licensed under this
+               Public License, and include the text of, or the URI or
+               hyperlink to, this Public License.
+
+       2. You may satisfy the conditions in Section 3(a)(1) in any
+          reasonable manner based on the medium, means, and context in
+          which You Share the Licensed Material. For example, it may be
+          reasonable to satisfy the conditions by providing a URI or
+          hyperlink to a resource that includes the required
+          information.
+
+       3. If requested by the Licensor, You must remove any of the
+          information required by Section 3(a)(1)(A) to the extent
+          reasonably practicable.
+
+       4. If You Share Adapted Material You produce, the Adapter's
+          License You apply must not prevent recipients of the Adapted
+          Material from complying with this Public License.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+  a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+     to extract, reuse, reproduce, and Share all or a substantial
+     portion of the contents of the database;
+
+  b. if You include all or a substantial portion of the database
+     contents in a database in which You have Sui Generis Database
+     Rights, then the database in which You have Sui Generis Database
+     Rights (but not its individual contents) is Adapted Material; and
+
+  c. You must comply with the conditions in Section 3(a) if You Share
+     all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+  c. The disclaimer of warranties and limitation of liability provided
+     above shall be interpreted in a manner that, to the extent
+     possible, most closely approximates an absolute disclaimer and
+     waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+  a. This Public License applies for the term of the Copyright and
+     Similar Rights licensed here. However, if You fail to comply with
+     this Public License, then Your rights under this Public License
+     terminate automatically.
+
+  b. Where Your right to use the Licensed Material has terminated under
+     Section 6(a), it reinstates:
+
+       1. automatically as of the date the violation is cured, provided
+          it is cured within 30 days of Your discovery of the
+          violation; or
+
+       2. upon express reinstatement by the Licensor.
+
+     For the avoidance of doubt, this Section 6(b) does not affect any
+     right the Licensor may have to seek remedies for Your violations
+     of this Public License.
+
+  c. For the avoidance of doubt, the Licensor may also offer the
+     Licensed Material under separate terms or conditions or stop
+     distributing the Licensed Material at any time; however, doing so
+     will not terminate this Public License.
+
+  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+     License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+  a. The Licensor shall not be bound by any additional or different
+     terms or conditions communicated by You unless expressly agreed.
+
+  b. Any arrangements, understandings, or agreements regarding the
+     Licensed Material not stated herein are separate from and
+     independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+  a. For the avoidance of doubt, this Public License does not, and
+     shall not be interpreted to, reduce, limit, restrict, or impose
+     conditions on any use of the Licensed Material that could lawfully
+     be made without permission under this Public License.
+
+  b. To the extent possible, if any provision of this Public License is
+     deemed unenforceable, it shall be automatically reformed to the
+     minimum extent necessary to make it enforceable. If the provision
+     cannot be reformed, it shall be severed from this Public License
+     without affecting the enforceability of the remaining terms and
+     conditions.
+
+  c. No term or condition of this Public License will be waived and no
+     failure to comply consented to unless expressly agreed to by the
+     Licensor.
+
+  d. Nothing in this Public License constitutes or may be interpreted
+     as a limitation upon, or waiver of, any privileges and immunities
+     that apply to the Licensor or You, including from the legal
+     processes of any jurisdiction or authority.

+ 198 - 0
README.md

@@ -0,0 +1,198 @@
+# 1024-channel electrophysiological recordings during resting state in V1 and V4 of macaque visual cortex
+This respository contains the data associated to the publication "1024-channel electrophysiological recordings during resting state in V1 and V4 of macaque visual cortex" by Chen\*, Morales-Gregorio\* et al. Future updates of the dataset will be uploaded [here](https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data).
+
+
+## Summary
+Electrophysiological activity data was recorded from the visual cortex (V1, V4) of two rhesus macaques using 16 utah arrays, for a total of 1024 recording sites. The monkeys were instructed to perform several tasks:
+* Resting state (RS),
+* Receptive field mapping (RF) with sweeping bars,
+* Signal to noise ratio (SNR) estimation from visual stimulation with a checkerboard.
+
+All data was recorded at the Netherlands Institute of Neuroscience and processed jointly with the INM-6 at Juelich research center.
+
+The raw data constist on the continuous measure of extracellular potentials at a sampling frequency of 30 kHz The raw data was processed into two widely used analog signals, the local field potential (LFP) and the multiunit activity envelope (MUAe), with sampling rates of 500 Hz and 1 kHz respectively. Metadata about the recording system, animal behaviour during the recordings, data quality and receptive field locations was collected and compiled into a single `.odml` file per session, provided under the `\data` directory of this repository.
+
+The following sessions and datafiles are available:
+
+<table>
+<thead>
+  <tr>
+    <th>Subject</th>
+    <th>Task type</th>
+    <th>Date of recording</th>
+    <th>Links to ressources<br></th>
+  </tr>
+</thead>
+<tbody>
+  <tr>
+    <td rowspan="8">L</td>
+    <td rowspan="2">Receptive Fields (RF)</td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_260617">26-06-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_260617/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_260617/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_260617/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_280617">28-06-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_280617/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_280617/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RF_280617/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td rowspan="3">Stimulus response (SNR)<br></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_250717">25-07-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_250717/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_250717/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_250717/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_090817">09-08-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_090817/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_090817/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_090817/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_100817">10-08-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_100817/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_100817/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_SNR_100817/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td rowspan="3">Resting State (RS)</td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_250717">25-07-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_250717/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_250717/eye_signals">Eye signals</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_250717/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_250717/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_090817">09-08-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_090817/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_090817/eye_signals">Eye signals</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_090817/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_090817/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_100817">10-08-2017</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_100817/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_100817/eye_signals">Eye signals</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_100817/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/L_RS_100817/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td rowspan="8">A</td>
+    <td rowspan="2">Receptive Fields (RF)</td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_280818">28-08-2018</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_280818/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_280818/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_280818/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_290818">29-08-2018</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_290818/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_290818/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RF_290818/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td rowspan="3">Stimulus response (SNR)<br></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_140819">14-08-2019</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_140819/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_140819/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_140819/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_150819">15-08-2019</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_150819/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_150819/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_150819/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_160819">16-08-2019</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_160819/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_160819/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_SNR_160819/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td rowspan="3">Resting State (RS)</td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_140819">14-08-2019</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_140819/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_140819/eye_signals">Eye signals</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_140819/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_140819/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_150819">15-08-2019</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_150819/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_150819/eye_signals">Eye signals</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_150819/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_150819/LFP">LFP</a></td>
+  </tr>
+  <tr>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_160819">16-08-2019</a></td>
+    <td><a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_160819/raw">Raw files</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_160819/eye_signals">Eye signals</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_160819/MUAe">MUAe</a> |
+    <a href="https://gin.g-node.org/NIN/V1_V4_1024_electrode_resting_state_data/src/master/data/A_RS_160819/LFP">LFP</a></td>
+  </tr>
+</tbody>
+</table>
+
+*Note:* The links in the table above point to the latest version of the data repository and not to the published instance.
+
+## Downloading the data
+### Using gin
+
+Create an account on gin and download the gin client as described [here](https://gin.g-node.org/G-Node/Info/wiki/GIN+CLI+Setup).
+On your computer, log in using:
+
+```sh
+gin login
+```
+
+Clone the repository using:
+
+```sh
+gin get NIN/V1_V4_1024_electrode_resting_state_data
+```
+The cloning step can take a long time, due to the large amount of individual files. Please be patient.
+
+Large data files will not be downloaded automatically, they will appear as git-annex links instead. We recommend downloading only the files you need, since the entire dataset is large. To get the contents of a certain file:
+
+```sh
+gin get-content <filename>
+```
+
+Downloaded large files will be locked (read-only). You must unlock the files using:
+
+```sh
+gin unlock <filename>
+```
+
+To remove the contents of a large file again, use:
+
+```sh
+gin lock <filename>
+gin remove-content <filename>
+```
+
+Detailed description of the gin client can be found at the [gin wiki](https://gin.g-node.org/G-Node/Info/wiki/). See the gin [usage tutorial](https://gin.g-node.org/G-Node/Info/wiki/GIN+CLI+Usage+Tutorial) for advanced features.
+
+### Using the web browser
+
+Download the files you want by clicking download in the gin web interface. Convenience summary tables of the data and sessions can be found in the summary above.
+
+## Citation policy
+
+Cite this work by citing the original publication.
+
+## Contact information
+
+For any inquiries contact the corresponding author(s) of the original publication.
+
+
+## License
+<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />The data and metadata in this work are licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
+
+Python and Matlab code in this repository are licensed under the BSD 3-clause license.
+
+The matlab-based NPMK package provided within this repository is re-distributed under the BSD 3-clause license, in compliance with the original licensing terms.

+ 11 - 0
code/LICENSE

@@ -0,0 +1,11 @@
+Copyright 2021 Xing Chen, Aitor Morales-Gregorio, Julia Sprenger, Alexander Kleinjohann, Shashwat Sridhar, Sacha J. van Albada, Sonja Grün and Pieter R. Roelfsema
+
+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.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+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.

+ 10 - 0
code/README.md

@@ -0,0 +1,10 @@
+# Code
+Here you can find the folders that contain the matlab and python scripts used in this project. 
+
+See the README files in their respective folders for more usage details.
+
+## License
+
+Python and Matlab code in this repository are licensed under the BSD 3-clause license.
+
+The matlab-based NPMK package provided within this repository is re-distributed under the BSD 3-clause license, in compliance with the original licensing terms.

+ 11 - 0
code/matlab_scripts/NPMK/@KTFigure/.svn/all-wcprops

@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 35
+/svnroot/npmk/!svn/ver/15/@KTFigure
+END
+KTFigure.m
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svnroot/npmk/!svn/ver/15/@KTFigure/KTFigure.m
+END

+ 62 - 0
code/matlab_scripts/NPMK/@KTFigure/.svn/entries

@@ -0,0 +1,62 @@
+10
+
+dir
+42
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/@KTFigure
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2010-12-23T18:16:55.094307Z
+15
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+KTFigure.m
+file
+
+
+
+
+2011-10-27T11:57:49.000000Z
+f9ab77035fb67ad3ef3e274b35fe0a36
+2010-12-23T18:16:55.094307Z
+15
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1619
+

+ 48 - 0
code/matlab_scripts/NPMK/@KTFigure/.svn/text-base/KTFigure.m.svn-base

@@ -0,0 +1,48 @@
+classdef KTFigure
+    properties (Hidden, SetAccess = private, GetAccess = private)
+        figureHandle
+    end
+    methods (Hidden)
+        function obj = KTFigure
+            obj.figureHandle = figure;
+            set(obj.figureHandle, 'Visible', 'off');
+        end
+        function screenSize = getScreenSize(~)
+            screenSize = get(0, 'ScreenSize');
+        end
+    end
+    methods
+        function handle = getHandle(obj)
+            handle = obj.figureHandle;
+        end
+        function EnlargeFigure(obj)
+            screenSize = obj.getScreenSize;
+            set(gcf, 'position', [screenSize(3:4).*[1.7, 1]*0.1 screenSize(3:4).*[1, 1.3]*0.6]);
+        end
+        function EnlargeFigureWide(obj)
+            screenSize = obj.getScreenSize;
+            set(gcf, 'position', [screenSize(3:4).*[0.3, 1]*0.1 screenSize(3:4).*[1.55, 1.3]*0.6]);
+        end
+        function HideFigure(obj)
+            set(obj.figureHandle, 'Visible', 'off');
+        end
+        function ShowFigure(obj)
+            set(obj.figureHandle, 'Visible', 'on');
+        end
+        function MakeBackgroundWhite(obj)
+            set(obj.figureHandle, 'color', [1 1 1]);
+        end
+        function MakeBackgroundGray(obj)
+            set(obj.figureHandle, 'color', [0.5 0.5 0.5]);
+        end
+        function MakeBackgroundBlack(obj)
+            set(obj.figureHandle, 'color', [0 0 0]);
+        end
+        function SetActive(obj)
+            figure(obj.figureHandle);
+        end
+        function CloseFigure(obj)
+            close(obj.figureHandle);
+        end
+    end
+end

+ 48 - 0
code/matlab_scripts/NPMK/@KTFigure/KTFigure.m

@@ -0,0 +1,48 @@
+classdef KTFigure
+    properties (Hidden, SetAccess = private, GetAccess = private)
+        figureHandle
+    end
+    methods (Hidden)
+        function obj = KTFigure
+            obj.figureHandle = figure;
+            set(obj.figureHandle, 'Visible', 'off');
+        end
+        function screenSize = getScreenSize(~)
+            screenSize = get(0, 'ScreenSize');
+        end
+    end
+    methods
+        function handle = getHandle(obj)
+            handle = obj.figureHandle;
+        end
+        function EnlargeFigure(obj)
+            screenSize = obj.getScreenSize;
+            set(gcf, 'position', [screenSize(3:4).*[1.7, 1]*0.1 screenSize(3:4).*[1, 1.3]*0.6]);
+        end
+        function EnlargeFigureWide(obj)
+            screenSize = obj.getScreenSize;
+            set(gcf, 'position', [screenSize(3:4).*[0.3, 1]*0.1 screenSize(3:4).*[1.55, 1.3]*0.6]);
+        end
+        function HideFigure(obj)
+            set(obj.figureHandle, 'Visible', 'off');
+        end
+        function ShowFigure(obj)
+            set(obj.figureHandle, 'Visible', 'on');
+        end
+        function MakeBackgroundWhite(obj)
+            set(obj.figureHandle, 'color', [1 1 1]);
+        end
+        function MakeBackgroundGray(obj)
+            set(obj.figureHandle, 'color', [0.5 0.5 0.5]);
+        end
+        function MakeBackgroundBlack(obj)
+            set(obj.figureHandle, 'color', [0 0 0]);
+        end
+        function SetActive(obj)
+            figure(obj.figureHandle);
+        end
+        function CloseFigure(obj)
+            close(obj.figureHandle);
+        end
+    end
+end

+ 11 - 0
code/matlab_scripts/NPMK/@KTFigureAxis/.svn/all-wcprops

@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svnroot/npmk/!svn/ver/15/@KTFigureAxis
+END
+KTFigureAxis.m
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svnroot/npmk/!svn/ver/15/@KTFigureAxis/KTFigureAxis.m
+END

+ 62 - 0
code/matlab_scripts/NPMK/@KTFigureAxis/.svn/entries

@@ -0,0 +1,62 @@
+10
+
+dir
+42
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/@KTFigureAxis
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2010-12-23T18:16:55.094307Z
+15
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+KTFigureAxis.m
+file
+
+
+
+
+2011-10-27T11:57:49.000000Z
+c7d88344edd087dfcc8bf6d7c5571bfc
+2010-12-23T18:16:55.094307Z
+15
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3052
+

+ 79 - 0
code/matlab_scripts/NPMK/@KTFigureAxis/.svn/text-base/KTFigureAxis.m.svn-base

@@ -0,0 +1,79 @@
+classdef KTFigureAxis
+    properties (Access = public)
+        linSpaceX = 20;
+        linSpaceY = 20;
+        lowerLimitX
+        lowerLimitY
+        upperLimitX
+        upperLimitY
+        axisHandle
+    end
+    methods (Hidden)
+        function obj = KTFigureAxis(lowerLimitX, upperLimitX, lowerLimitY, upperLimitY, axisHandle)
+            switch nargin
+                case 0
+                    obj.axisHandle = gca;
+                    disp('Set the limits.');
+                case 4
+                    obj.lowerLimitX = lowerLimitX;
+                    obj.upperLimitX = upperLimitX;
+                    obj.lowerLimitY = lowerLimitY;
+                    obj.upperLimitY = upperLimitY;
+                    obj.axisHandle  = gca;
+                case 5
+                    obj.lowerLimitX = lowerLimitX;
+                    obj.upperLimitX = upperLimitX;
+                    obj.lowerLimitY = lowerLimitY;
+                    obj.upperLimitY = upperLimitY;
+                    obj.axisHandle  = axisHandle;                  
+                otherwise
+                    disp('Number of input arguments is invalid.');
+            end
+        end
+    end
+    methods
+        function obj = set.lowerLimitX(obj, limit)
+            obj.lowerLimitX = limit;
+        end
+        function obj = set.upperLimitX(obj, limit)
+            obj.upperLimitX = limit;
+        end
+        function obj = set.lowerLimitY(obj, limit)
+            obj.lowerLimitY = limit;
+        end
+        function obj = set.upperLimitY(obj, limit)
+            obj.upperLimitY = limit;
+        end
+        function obj = set.axisHandle(obj, limit)
+            obj.axisHandle = limit;
+        end
+        function obj = set.linSpaceX(obj, spacing)
+            obj.linSpaceX = spacing;
+        end
+        function obj = set.linSpaceY(obj, spacing)
+            obj.linSpaceY = spacing;
+        end
+        function setXLabels(obj)
+            xLim = get(gca, 'XLim');
+            XTickMarkLocations = linspace(xLim(1), xLim(2), obj.linSpaceX);
+            XTickMarkLabelsLocations = linspace(obj.lowerLimitX, obj.upperLimitX, obj.linSpaceX);
+            for labelIDX = 1:obj.linSpaceX
+                XTickMarkLabels{labelIDX} = num2str(roundn(XTickMarkLabelsLocations(labelIDX),1));
+            end
+            set(obj.axisHandle, ...
+                'XTick', XTickMarkLocations,...
+                'XTickLabel', XTickMarkLabels);
+        end
+        function setYLabels(obj)
+            yLim = get(gca, 'YLim');
+            YTickMarkLocations = linspace(yLim(1), yLim(2), obj.linSpaceY);
+            YTickMarkLabelsLocations = linspace(obj.lowerLimitY, obj.upperLimitY, obj.linSpaceY);
+            for labelIDX = 1:obj.linSpaceY
+                YTickMarkLabels{labelIDX} = num2str(roundn(YTickMarkLabelsLocations(labelIDX),1));
+            end
+            set(obj.axisHandle, ...
+                'YTick', YTickMarkLocations,...
+                'YTickLabel', YTickMarkLabels);
+        end
+    end
+end

+ 79 - 0
code/matlab_scripts/NPMK/@KTFigureAxis/KTFigureAxis.m

@@ -0,0 +1,79 @@
+classdef KTFigureAxis
+    properties (Access = public)
+        linSpaceX = 20;
+        linSpaceY = 20;
+        lowerLimitX
+        lowerLimitY
+        upperLimitX
+        upperLimitY
+        axisHandle
+    end
+    methods (Hidden)
+        function obj = KTFigureAxis(lowerLimitX, upperLimitX, lowerLimitY, upperLimitY, axisHandle)
+            switch nargin
+                case 0
+                    obj.axisHandle = gca;
+                    disp('Set the limits.');
+                case 4
+                    obj.lowerLimitX = lowerLimitX;
+                    obj.upperLimitX = upperLimitX;
+                    obj.lowerLimitY = lowerLimitY;
+                    obj.upperLimitY = upperLimitY;
+                    obj.axisHandle  = gca;
+                case 5
+                    obj.lowerLimitX = lowerLimitX;
+                    obj.upperLimitX = upperLimitX;
+                    obj.lowerLimitY = lowerLimitY;
+                    obj.upperLimitY = upperLimitY;
+                    obj.axisHandle  = axisHandle;                  
+                otherwise
+                    disp('Number of input arguments is invalid.');
+            end
+        end
+    end
+    methods
+        function obj = set.lowerLimitX(obj, limit)
+            obj.lowerLimitX = limit;
+        end
+        function obj = set.upperLimitX(obj, limit)
+            obj.upperLimitX = limit;
+        end
+        function obj = set.lowerLimitY(obj, limit)
+            obj.lowerLimitY = limit;
+        end
+        function obj = set.upperLimitY(obj, limit)
+            obj.upperLimitY = limit;
+        end
+        function obj = set.axisHandle(obj, limit)
+            obj.axisHandle = limit;
+        end
+        function obj = set.linSpaceX(obj, spacing)
+            obj.linSpaceX = spacing;
+        end
+        function obj = set.linSpaceY(obj, spacing)
+            obj.linSpaceY = spacing;
+        end
+        function setXLabels(obj)
+            xLim = get(gca, 'XLim');
+            XTickMarkLocations = linspace(xLim(1), xLim(2), obj.linSpaceX);
+            XTickMarkLabelsLocations = linspace(obj.lowerLimitX, obj.upperLimitX, obj.linSpaceX);
+            for labelIDX = 1:obj.linSpaceX
+                XTickMarkLabels{labelIDX} = num2str(roundn(XTickMarkLabelsLocations(labelIDX),1));
+            end
+            set(obj.axisHandle, ...
+                'XTick', XTickMarkLocations,...
+                'XTickLabel', XTickMarkLabels);
+        end
+        function setYLabels(obj)
+            yLim = get(gca, 'YLim');
+            YTickMarkLocations = linspace(yLim(1), yLim(2), obj.linSpaceY);
+            YTickMarkLabelsLocations = linspace(obj.lowerLimitY, obj.upperLimitY, obj.linSpaceY);
+            for labelIDX = 1:obj.linSpaceY
+                YTickMarkLabels{labelIDX} = num2str(roundn(YTickMarkLabelsLocations(labelIDX),1));
+            end
+            set(obj.axisHandle, ...
+                'YTick', YTickMarkLocations,...
+                'YTickLabel', YTickMarkLabels);
+        end
+    end
+end

+ 131 - 0
code/matlab_scripts/NPMK/@KTNEVComments/KTNEVComments.m

@@ -0,0 +1,131 @@
+%
+% KTNEVComments
+% 
+% This is a class that deals with comments saved in a NEV file. The user
+% can read the comments, get their timestamp information and even add
+% comments to the NEV file and then save it as a new file.
+% 
+%
+%   addComment:              Allows the user to add a new comment to the
+%                            file at a given timestamp.
+%                 
+%   displayComments:         Displays all the comments in the NEV with their
+%                            corresponding timestamps.
+%
+%   'report':                Will show a summary report if user passes this
+%                            argument.
+%                            DEFAULT: will not show report.
+%
+%   getCommentText:          Displays the text of comments.
+%
+%   getCommentTimestamps:    Displays the timestamp of comments, in samples.
+%
+%   getCommentTimestampsSec: Displays the timestamp of comments, in seconds.
+%
+%   EXAMPLE:
+%
+%   To run, use "myVariable = KTNEVComments;". Then use
+%   "myVariable.METHODNAME" to call the various differnet methods. Type
+%   "myVariable." and then hit enter to see the available methods.
+%
+%   myComments = KTNEVComments;
+%   myComments.DisplayComments;
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.0.1.0
+%
+
+classdef KTNEVComments
+    
+    properties (Hidden)
+        NEV
+    end
+    methods (Hidden)
+        function obj = KTNEVComments
+            %% Open the NEV file
+            obj.NEV = openNEV('read', 'nomat');
+
+        end
+        function rawNEV = getRawNEV(obj)
+        	FIDr = fopen([obj.NEV.MetaTags.FilePath '/' obj.NEV.MetaTags.Filename '.NEV'], 'r+', 'ieee-le');
+        
+            % Loading the NEV file
+            rawNEV = fread(FIDr)';
+            fclose(FIDr);
+        end
+        function rawData = getRawData(obj)
+            FID = fopen([obj.NEV.MetaTags.FilePath '/' obj.NEV.MetaTags.Filename '.NEV'], 'r+', 'ieee-le');
+            fseek(FID, obj.NEV.MetaTags.HeaderOffset, 'bof');
+            rawData  = fread(FID, [obj.NEV.MetaTags.PacketBytes obj.NEV.MetaTags.PacketCount], '104*uint8=>uint8', 0);            
+            
+        end
+        function packetIndices = getPacketIDIndices(obj)
+            rawData = obj.getRawData;
+            PacketID  = rawData(5:6,:);
+            packetIndices = typecast(PacketID(:), 'uint16').';
+        end
+        function packetIndices = getPacketIDIndicesForPacketID(obj, packetID)
+            PacketIDs = obj.getPacketIDIndices;
+            packetIndices = find(PacketIDs==packetID);
+        end
+        function timestampIndices = getTimestampIndices(obj)
+            rawData = obj.getRawData;
+            Timestamp = rawData(1:4,:);
+            timestampIndices = typecast(Timestamp(:), 'uint32').';
+        end
+    end
+    methods
+        function displayComments(obj)
+            fprintf('\n\n  Timestamp     Timestamp Seconds     Text\n');
+            for commentIDX = 1:length(obj.NEV.Data.Comments.TimeStamp)
+                fprintf('%11d     %17.4f     %s\n', obj.NEV.Data.Comments.TimeStamp(commentIDX), ...
+                                                    obj.NEV.Data.Comments.TimeStampSec(commentIDX), ...
+                                                    obj.NEV.Data.Comments.Text(commentIDX,:));
+            end
+        end
+        function output = getCommentTimestamps(obj)
+            output = obj.NEV.Data.Comments.TimeStamp;
+        end
+        function output = getCommentTimestampsSec(obj)
+            output = obj.NEV.Data.Comments.TimeStampSec;
+        end
+        function output = getCommentText(obj)
+            output = obj.NEV.Data.Comments.Text;            
+        end
+        function addComment(obj)
+            FIDw = fopen([obj.NEV.MetaTags.FilePath '/' obj.NEV.MetaTags.Filename '-commented.nev'], 'w+', 'ieee-le'); 
+            
+            % Getting the comment info
+            timestamp = input('What timestamp? ');
+            color = input('What is the color code (hit enter if not sure)? ');
+            if isempty(color)
+                color = 0;
+            end
+            charSet = input('What is the character set (hit enter if not sure)? ');
+            if isempty(charSet)
+                charSet = 0;
+            end
+            text = input('Comment: ','s');
+            
+            text(end+1:92) = zeros(1,obj.NEV.MetaTags.PacketBytes-12-length(text));
+            
+            % Reading the RawNEV
+            rawData = obj.getRawNEV;
+
+            rawData = [rawData typecast(uint32(timestamp), 'uint8')...
+                               typecast(uint16(65535), 'uint8')...
+                               typecast(uint8(charSet), 'uint8')...
+                               typecast(uint8(0), 'uint8')...
+                               typecast(uint32(color), 'uint8')...
+                               typecast(uint8(text), 'uint8')];
+            
+            
+            % Writing file
+            fwrite(FIDw, rawData, 'uint8');
+            fclose(FIDw);
+            clear rawData;
+        end
+    end
+end

+ 11 - 0
code/matlab_scripts/NPMK/@KTNSPOnline/.svn/all-wcprops

@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svnroot/npmk/!svn/ver/47/@KTNSPOnline
+END
+KTNSPOnline.m
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/npmk/!svn/ver/51/@KTNSPOnline/KTNSPOnline.m
+END

+ 62 - 0
code/matlab_scripts/NPMK/@KTNSPOnline/.svn/entries

@@ -0,0 +1,62 @@
+10
+
+dir
+47
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/@KTNSPOnline
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2012-03-27T23:38:47.453382Z
+47
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+KTNSPOnline.m
+file
+51
+
+
+
+2011-12-08T21:00:27.000000Z
+ddb9405dadccf2d4fceffc1b4abe26fa
+2012-03-27T23:44:26.915984Z
+51
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+19793
+

+ 470 - 0
code/matlab_scripts/NPMK/@KTNSPOnline/.svn/text-base/KTNSPOnline.m.svn-base

@@ -0,0 +1,470 @@
+classdef KTNSPOnline
+
+% UEAMAPFILE -- Defines a class that contains information on a UEA
+% electrode array using CMP files provided by Blackrock Microsystems.
+%
+% To load a CMP file type 'MapName = UEAMapFile' where MapName is the name
+% of the variable that will be created and will contain the map class.
+%
+% Example: myArrayMap = UEAMapFile;
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% METHODS:
+%
+% There are several available methods for mapfiles. Here's a list and a
+% description of what they perform.
+%
+% Electrode2Channel(Electrode): 
+%   Will return the Channel number corresponding to a passed Electrode.
+%
+% Channel2Electrode(Channel):   
+%   Will return the Electrode number corresponding to a passed Channel.
+%
+% GetChannelBankID(Channel):
+%   Returns the BankID for a passed Channel.
+%
+% GetChannelPin(Channel):
+%   Returns the Pin for a passed Channel.
+%
+% GetChannelLabel(Channel):
+%   Returns the Label for a passed Channel.
+%
+% GenerateChannelSubplot(Channel):
+%   Returns a subplot handle for the passed Channel to be used in plotting
+%   UEA-like maps.
+%
+% GenerateChannelSubplotNames(Channel):
+%   Plots the names of channels and electrodes on the subplot corresponding
+%   to the passed Channel.
+%
+% GetChannelColumnRow(Channel):
+%   Returns the Column and Row positions of the passed number that is used
+%   to plot UEA-like maps.
+%
+% PlotCMP:
+%   Will plot a map of the CMP Map with all the electrode and channel
+%   names.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Version 1.1.0.0
+
+
+%%
+    properties (Hidden)
+        NSPHandle
+        dataCollectionFlag
+        contCollection
+        allSpikeData
+        allLFPData
+    end
+    methods (Hidden)
+        function obj = KTNSPOnline
+            disp('Initializing NSP Connection...');
+            try
+                cbmex('open');
+            catch
+                fprintf(2,'Error connecting to NSP... Please make sure the NSP or nPlayServer is running and try again.\n');
+                return;
+            end
+            obj.contCollection = 0;
+            obj.dataCollectionFlag = 0;
+            obj.dataCollectionStart;
+        end
+    end
+    methods
+        %% NSP Interface Mthods
+        function closeConnection(obj)
+            cbmex('close');
+        end
+        function openConnection(obj)
+            cbmex('open');
+        end
+        function NSPTime = getNSPTimeSeconds(obj)
+            NSPTime = cbmex('time');
+        end
+        function NSPTime = getNSPTimeSamples(obj)
+            NSPTime = cbmex('time') * 30000;
+        end
+        
+        %% Data Recording Methods
+        function recordingStart(obj, fileName, userComment)
+            if ~exist('userComment', 'var')
+                userComment = 'KTNSPOnline triggered.';
+            end
+            if ~exist('fileName', 'var')
+                fprintf(2,'Error...\n');
+                disp('Filename is a required parameter.');
+            else
+                cbmex('fileconfig', fileName, userComment, 1);
+                pause(0.1);
+                cbmex('fileconfig', fileName, userComment, 1);
+            end
+        end
+        function recordingStop(obj)
+            cbmex('fileconfig', '', '', 0);
+        end
+        
+        %% Output Methods
+        function sendNSPComment(obj, comment)
+            if ischar(comment)
+                cbmex('comment', 0, comment);
+            else
+                fprintf(2,'Error...\n');
+                disp('The comment should be an ASCII string.');
+            end
+        end
+        function sendNSPMarker(obj, markerValue)
+            if isnumeric(markerValue) && markerValue <= 255
+                cbmex('comment', markerValue);
+            else
+                fprintf(2,'Error...\n');
+                disp('The marker value should be a number less than 255.');
+            end
+        end
+        function setDigOutTTLHigh(obj, digOutPortNum)
+            digOutPortNum = digOutPortNum + 152;
+            cbmex('digitalout', digOutPortNum, 1);
+        end
+        function setDigOutTTLLow(obj, digOutPortNum)
+            digOutPortNum = digOutPortNum + 152;
+            cbmex('digitalout', digOutPortNum, 0);
+        end
+        function setDigOutPulse(obj, digOutPortNum, pulseCount, frequency, pulseWidth)
+            if ~exist('digOutPortNum', 'var') || ...
+                    ~exist('pulseCount', 'var') || ...
+                    ~exist('frequency', 'var') || ...
+                    ~exist('pulseWidth', 'var')
+                fprintf(2,'The function requires the following inputs:\n');
+                disp('1. Digital Output (digOutPortNum): The digital out port to be triggered.');
+                disp('2. Pulse Count (pulseCount):       The number of pulses to be sent out of digital out.');
+                disp('3. Frequency (frequency):          The frequency of the output signal.');
+                disp('4. Pulse Width (pulseWidth):       The width of the output TTL pulse.');
+                disp('Example: object.setDigOutPulse(1, 10, 100, 0.01);');
+            else
+                digOutPortNum = digOutPortNum + 152;
+                for idx = 1:pulseCount
+                    cbmex('digitalout', digOutPortNum, 1);
+                    pause(pulseWidth);
+                    cbmex('digitalout', digOutPortNum, 0);
+                    pause(1/frequency - pulseWidth);
+                end
+            end    
+        end
+        function setAnaOutPulse(obj, anaOutPortNum, pulseCount, frequency, pulseWidth)
+            if ~exist('anaOutPortNum', 'var') || ...
+                    ~exist('pulseCount', 'var') || ...
+                    ~exist('frequency', 'var') || ...
+                    ~exist('pulseWidth', 'var')
+                fprintf(2,'The function requires the following inputs:\n');
+                disp('1. Analog Output (anaOutPortNum): The analog out port to be triggered.');
+                disp('2. Pulse Count (pulseCount):      The number of pulses to be sent out of analog out.');
+                disp('3. Frequency (frequency):         The frequency of the output signal.');
+                disp('4. Pulse Width (pulseWidth):      The width of the output TTL pulse in milliseconds.');
+                disp('Example: object.setAnaOutPulse(1, 10, 100, 0.01);');
+            else
+                anaOutPortNum = anaOutPortNum + 144;
+                cbmex('analogout', anaOutPortNum, 'pulses', [pulseCount 0 pulseWidth pulseWidth 4000 0 0 0], 'ms', 'mv')
+            end                
+        end
+        
+        %% Data Collection Methods
+%         function status = dataCollectionIsActive(obj)
+%             try
+%                 activeFlag = cbmex('trialdata', 1)
+%             catch
+%                 status = 0;
+%                 disp('Data collection is not active.');
+%                 return;
+%             end
+%             disp('Data is currently being collected...');
+%             status = 1;
+%         end
+        function status = dataCollectionStart(BA)
+%             if ~BA.dataCollectionIsActive
+                disp('Starting to collect data now...');
+                cbmex('trialconfig', 1);
+%             end
+%             BA.dataCollectionFlag = 1;
+        end
+        function dataCollectionStop(obj)
+%             if obj.dataCollectionIsActive
+                disp('Data collection is now stopped.');
+                cbmex('trialconfig', 0);
+%             end
+%             obj.dataCollectionFlag = 0;
+        end
+%         function dataCollectionSetContActive(obj)
+%             disp('Continuous data collection is now active.');
+%             fprintf(2, 'Do not change any channel sampling frequency while continuous data collection is active.\n');
+%             obj.ContCollection = 1;
+%         end
+        function [spikeData, startTime, LFPData] = dataCollectionReadBuffer(obj)    
+            try
+                [spikeData, startTime, LFPData] = cbmex('trialdata', 1);
+            catch
+                fprintf(2,'Error...\n');
+                disp('Data collection is not active.');
+                disp('Use dataCollectionStart method to start locating.');
+            end
+%             if obj.contCollection
+%                 numChannelsRead = size(LFPData,1);
+%                 if isempty(obj.allLFPData)
+%                     obj.allLFPData = LFPData;
+%                 else
+%                     for idx = 1:numChannelsRead
+%                         obj.allLFPData{idx, 3} = [obj.allLFPData{idx, 3}; LFPData{idx, 3}];
+%                     end
+%                 end
+%             end
+        end
+%         function data = getDataLFPContinuous(obj)
+%             data = obj.allLFPData;
+%         end
+        
+        %% Detection Methods
+        function spikedChannels = detectChannelsFired(obj, units)
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            spikeData = dataCollectionReadBuffer(obj);
+            spikeData(:,1) = [];
+            spikedChannels = ~cellfun(@isempty, spikeData(:,units));
+        end
+        function fireFlag = detectChannelUnitFiredAny(obj, channels, units)
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            spikedChannels = obj.detectChannelsFired(units);
+            fireFlag = any(any(spikedChannels(channels, units)));
+        end
+        function fireFlag = detectChannelUnitFiredAll(obj, channels, units)
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            spikedChannels = obj.detectChannelsFired(units);
+            fireFlag = all(all(spikedChannels(channels, units)));
+        end
+        function fireFlag = detectWhenChannelUnitFiredAny(obj, channels, units, timeWindow)
+            fireFlag = 0;
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            if ~exist('timeWindow', 'var')
+                timeWindow = 0.02;
+            end
+            while ~fireFlag
+                pause(timeWindow);
+                fireFlag = detectChannelUnitFiredAny(obj, channels, units);
+            end
+        end
+%         function fireFlag = detectWhenChannelUnitFiredAll(obj, channels, units, timeWindow)
+%             fireFlag = 0;
+%             if ~exist('units', 'var')
+%                 units = 1:5;
+%             end
+%             if ~exist('timeWindow', 'var')
+%                 timeWindow = 0.02;
+%             end
+%             while ~fireFlag
+%                 pause(timeWindow);
+%                 fireFlag = detectChannelUnitFiredAll(obj, channels, units);
+%             end
+%         end
+        function [bitValues, bitTimestamps] = detectDigInWord(obj)
+            readData = obj.dataCollectionReadBuffer;
+            bitValues = readData{151,3};
+            bitTimestamps = readData{151,2};
+        end
+        function [bitValues, bitTimestamps] = detectDigInBinary(obj)
+            readData = obj.dataCollectionReadBuffer;
+            bitValues = dec2bin(readData{151,3});
+            bitTimestamps = readData{151,2};
+        end
+% % % %         function fireFlag = detectDigInBit(obj, bitDetect)
+% % % %             fireFlag = 0;
+% % % %             if ~exist('bitDetect', 'var')
+% % % %                 disp('Please specify a bit that needs to be detected.');
+% % % %                 disp('Example: detectDigInBit(3)');
+% % % %                 return;
+% % % %             end
+% % % %             spikedChannels = obj.detectChannelsFired([1:5]);
+% % % %             if (bitDetect < 0) || (bitDetect > 15)
+% % % %                 disp('The bit value can be between 0 and 15, inclusive.');
+% % % %             else
+% % % %                 fireFlag = any(any(spikedChannels(136, 1:5)));
+% % % %             end
+% % % %         end
+        function fireFlag = detectWhenDigInWord(obj, wordValue, timeWindow)
+            fireFlag = 0;
+            if ~exist('wordValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('Please specify a word value that needs to be detected.');
+                disp('Example: detectDigInBit(128)');
+                return;
+            end
+            if ~exist('timeWindow', 'var')
+                timeWindow = 0.02;
+            end
+            while ~fireFlag
+                pause(timeWindow);
+                readWordValue = detectDigInWord(obj);
+                if wordValue == readWordValue
+                    fireFlag = 1;
+                end
+            end
+        end
+        function fireFlag = detectWhenDigInBit(obj, bitsValue, timeWindow)
+            fireFlag = 0;
+            if ~exist('bitValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('Please specify a bit pattern that needs to be detected.');
+                disp('Example: detectDigInBit(13)');
+                return;
+            end
+            if ~exist('timeWindow', 'var')
+                timeWindow = 0.02;
+            end
+            while ~fireFlag
+                pause(timeWindow);
+                bitsValue = detectDigInBit(obj, bitDetect);
+                if strcmpi(bitsValue, readWordValue)
+                    fireFlag = 1;
+                end
+            end
+        end
+        
+        %% Get Configuration Values
+        function configValue = getAllChannelLabels(obj)
+            configStream = cbmex('chanlabel');
+            configValue = configStream(:,1);
+        end
+        function configValue = getChannelLabel(obj, channel)
+            configStream = cbmex('chanlabel', channel);
+            configValue = configStream{1};
+        end
+        function isFlag = isChannelSpikeExtractionEnabled(obj, channel)
+            configStream = cbmex('chanlabel', channel);
+            isFlag = configStream{2};
+        end
+        function isFlag = isChannelUnitEnabled(obj, channel, unit)
+            configStream = cbmex('chanlabel', channel);
+            isFlag = configStream{unit};
+        end
+        function ampRejRange = getAmplitudeRejectionRange(obj, channel)
+            configStream = cbmex('config', channel);
+            ampRejRange = [configStream{12,2}, configStream{13,2}];               
+        end
+        function setAmplitudeRejectionRange(obj, channel, newValue)
+            if ~exist('newValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('newValue is a required argument.');
+                return;
+            end
+            if length(newValue)<2 || length(newValue)>2
+                fprintf(2,'Error...\n');
+                disp('The passed argument to this function should have two values: lower and higher amplitude rejection values, respectively.');
+                return;
+            end
+            if newValue(1)>=newValue(2)
+                fprintf(2,'Error...\n');
+                disp('The low amplitude rejection value should be smaller than the high value.');
+                return;
+            end
+            configStream = cbmex('config', channel, 'amplrejneg', newValue(1));
+            configStream = cbmex('config', channel, 'amplrejpos', newValue(2));          
+        end       
+        function spikeThresh = getSpikeThresholdValue(obj, channel)
+            configStream = cbmex('config', channel);
+            spikeThresh = ceil(configStream{10, 2}/4);
+        end
+        function setSpikeThresholdValue(obj, channel, newValue)
+            if ~exist('newValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('newValue is a required argument.');
+                return;
+            else
+                configStream = cbmex('config', channel, 'spkthrlevel', newValue * 4);
+            end
+        end
+        function refChan = getDigitalReferenceChannel(obj, channel)
+            configStream = cbmex('config', channel);
+            refChan = configStream{14,2};
+        end
+        function refChan = setDigitalReferenceChannel(obj, channel, newValue)
+            if ~exist('newValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('newValue is a required argument.');
+                return;
+            else
+                configStream = cbmex('config', channel, 'refelecchan', newValue);
+            end
+        end
+        
+        %% Data Analysis Methods
+        function onlineSpectogram(obj, frequencyRange)
+            if ~exist('frequencyRange', 'var')
+                fprintf(2,'Error...\n');
+                disp('You need to define a frequency range for this function.');
+                disp('Example: onlineSpectrogram([0.3, 7500]) to show the spectrogram in the range of 0.3 Hz to 7500 Hz.');
+                return;
+            end
+            frequencyRange = linspace(frequencyRange(1), frequencyRange(end), 150);
+            % All durations are in second
+            sampleCollectionDuration = 0.02;
+            refreshRate = 0.05;
+            % Setting up a default frequency range, if none is specified
+            if ~exist('frequencyRange', 'var')
+                disp('Frequency range was not specified. A default range of 0.3:1:7500 will be used.');
+                frequencyRange = 0.3:1:7500;
+            end
+            % Setting up the figure
+            procFigure = figure;
+            set(procFigure, 'Name', 'Close this figure to stop'); 
+            % Setting up collection variable
+            timeDisplay = tic;
+            timeCollection = tic;
+            flagCollection = 1;
+            % Collection
+            dataCollectionStart(obj);
+            while ishandle(procFigure)
+                pause(0.001);
+                if flagCollection
+                    timeCollectionET = toc(timeCollection);
+                    if timeCollectionET > sampleCollectionDuration
+                        [spikeData, startTime, contData] = dataCollectionReadBuffer(obj);
+                        nGraphs = size(contData,1);
+                        if ishandle(procFigure)
+                            for idx = 1:nGraphs
+                                fs0 = contData{idx, 2};
+                                data = contData{idx, 3};
+                                collectSize = min(size(data), sampleCollectionDuration * fs0);
+                                x = data(1:collectSize);
+                                if isempty(frequencyRange)
+                                    [psd, f] = periodogram(double(x),[],'onesided',512,fs0); 
+                                else
+                                    [psd, f] = periodogram(double(x),[],frequencyRange,fs0);
+                                end
+                                subplot(nGraphs,1,idx,'Parent',procFigure);
+                                psdLog = 10*log10(psd);
+                                plot(f, psdLog, 'b');
+                                title(sprintf('fs = %d t = %f',fs0, startTime));
+                                xlabel('Frequency (Hz)'); xlim([frequencyRange(1), frequencyRange(end)]);
+                                ylabel('Magnitude (dB)');
+                            end
+                            drawnow;
+                        end
+                        flagCollection = 0;
+                    end
+                end
+                timeCollectionET = toc(timeDisplay);
+                if timeCollectionET >= refreshRate;
+                    timeDisplay = tic;
+                    timeCollection = tic;
+                    flagCollection = 1;
+                end
+            end
+            dataCollectionStop(obj);
+        end       
+    end
+end

+ 470 - 0
code/matlab_scripts/NPMK/@KTNSPOnline/KTNSPOnline.m

@@ -0,0 +1,470 @@
+classdef KTNSPOnline
+
+% UEAMAPFILE -- Defines a class that contains information on a UEA
+% electrode array using CMP files provided by Blackrock Microsystems.
+%
+% To load a CMP file type 'MapName = UEAMapFile' where MapName is the name
+% of the variable that will be created and will contain the map class.
+%
+% Example: myArrayMap = UEAMapFile;
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% METHODS:
+%
+% There are several available methods for mapfiles. Here's a list and a
+% description of what they perform.
+%
+% Electrode2Channel(Electrode): 
+%   Will return the Channel number corresponding to a passed Electrode.
+%
+% Channel2Electrode(Channel):   
+%   Will return the Electrode number corresponding to a passed Channel.
+%
+% GetChannelBankID(Channel):
+%   Returns the BankID for a passed Channel.
+%
+% GetChannelPin(Channel):
+%   Returns the Pin for a passed Channel.
+%
+% GetChannelLabel(Channel):
+%   Returns the Label for a passed Channel.
+%
+% GenerateChannelSubplot(Channel):
+%   Returns a subplot handle for the passed Channel to be used in plotting
+%   UEA-like maps.
+%
+% GenerateChannelSubplotNames(Channel):
+%   Plots the names of channels and electrodes on the subplot corresponding
+%   to the passed Channel.
+%
+% GetChannelColumnRow(Channel):
+%   Returns the Column and Row positions of the passed number that is used
+%   to plot UEA-like maps.
+%
+% PlotCMP:
+%   Will plot a map of the CMP Map with all the electrode and channel
+%   names.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Version 1.1.0.0
+
+
+%%
+    properties (Hidden)
+        NSPHandle
+        dataCollectionFlag
+        contCollection
+        allSpikeData
+        allLFPData
+    end
+    methods (Hidden)
+        function obj = KTNSPOnline
+            disp('Initializing NSP Connection...');
+            try
+                cbmex('open');
+            catch
+                fprintf(2,'Error connecting to NSP... Please make sure the NSP or nPlayServer is running and try again.\n');
+                return;
+            end
+            obj.contCollection = 0;
+            obj.dataCollectionFlag = 0;
+            obj.dataCollectionStart;
+        end
+    end
+    methods
+        %% NSP Interface Mthods
+        function closeConnection(obj)
+            cbmex('close');
+        end
+        function openConnection(obj)
+            cbmex('open');
+        end
+        function NSPTime = getNSPTimeSeconds(obj)
+            NSPTime = cbmex('time');
+        end
+        function NSPTime = getNSPTimeSamples(obj)
+            NSPTime = cbmex('time') * 30000;
+        end
+        
+        %% Data Recording Methods
+        function recordingStart(obj, fileName, userComment)
+            if ~exist('userComment', 'var')
+                userComment = 'KTNSPOnline triggered.';
+            end
+            if ~exist('fileName', 'var')
+                fprintf(2,'Error...\n');
+                disp('Filename is a required parameter.');
+            else
+                cbmex('fileconfig', fileName, userComment, 1);
+                pause(0.1);
+                cbmex('fileconfig', fileName, userComment, 1);
+            end
+        end
+        function recordingStop(obj)
+            cbmex('fileconfig', '', '', 0);
+        end
+        
+        %% Output Methods
+        function sendNSPComment(obj, comment)
+            if ischar(comment)
+                cbmex('comment', 0, comment);
+            else
+                fprintf(2,'Error...\n');
+                disp('The comment should be an ASCII string.');
+            end
+        end
+        function sendNSPMarker(obj, markerValue)
+            if isnumeric(markerValue) && markerValue <= 255
+                cbmex('comment', markerValue);
+            else
+                fprintf(2,'Error...\n');
+                disp('The marker value should be a number less than 255.');
+            end
+        end
+        function setDigOutTTLHigh(obj, digOutPortNum)
+            digOutPortNum = digOutPortNum + 152;
+            cbmex('digitalout', digOutPortNum, 1);
+        end
+        function setDigOutTTLLow(obj, digOutPortNum)
+            digOutPortNum = digOutPortNum + 152;
+            cbmex('digitalout', digOutPortNum, 0);
+        end
+        function setDigOutPulse(obj, digOutPortNum, pulseCount, frequency, pulseWidth)
+            if ~exist('digOutPortNum', 'var') || ...
+                    ~exist('pulseCount', 'var') || ...
+                    ~exist('frequency', 'var') || ...
+                    ~exist('pulseWidth', 'var')
+                fprintf(2,'The function requires the following inputs:\n');
+                disp('1. Digital Output (digOutPortNum): The digital out port to be triggered.');
+                disp('2. Pulse Count (pulseCount):       The number of pulses to be sent out of digital out.');
+                disp('3. Frequency (frequency):          The frequency of the output signal.');
+                disp('4. Pulse Width (pulseWidth):       The width of the output TTL pulse.');
+                disp('Example: object.setDigOutPulse(1, 10, 100, 0.01);');
+            else
+                digOutPortNum = digOutPortNum + 152;
+                for idx = 1:pulseCount
+                    cbmex('digitalout', digOutPortNum, 1);
+                    pause(pulseWidth);
+                    cbmex('digitalout', digOutPortNum, 0);
+                    pause(1/frequency - pulseWidth);
+                end
+            end    
+        end
+        function setAnaOutPulse(obj, anaOutPortNum, pulseCount, frequency, pulseWidth)
+            if ~exist('anaOutPortNum', 'var') || ...
+                    ~exist('pulseCount', 'var') || ...
+                    ~exist('frequency', 'var') || ...
+                    ~exist('pulseWidth', 'var')
+                fprintf(2,'The function requires the following inputs:\n');
+                disp('1. Analog Output (anaOutPortNum): The analog out port to be triggered.');
+                disp('2. Pulse Count (pulseCount):      The number of pulses to be sent out of analog out.');
+                disp('3. Frequency (frequency):         The frequency of the output signal.');
+                disp('4. Pulse Width (pulseWidth):      The width of the output TTL pulse in milliseconds.');
+                disp('Example: object.setAnaOutPulse(1, 10, 100, 0.01);');
+            else
+                anaOutPortNum = anaOutPortNum + 144;
+                cbmex('analogout', anaOutPortNum, 'pulses', [pulseCount 0 pulseWidth pulseWidth 4000 0 0 0], 'ms', 'mv')
+            end                
+        end
+        
+        %% Data Collection Methods
+%         function status = dataCollectionIsActive(obj)
+%             try
+%                 activeFlag = cbmex('trialdata', 1)
+%             catch
+%                 status = 0;
+%                 disp('Data collection is not active.');
+%                 return;
+%             end
+%             disp('Data is currently being collected...');
+%             status = 1;
+%         end
+        function status = dataCollectionStart(BA)
+%             if ~BA.dataCollectionIsActive
+                disp('Starting to collect data now...');
+                cbmex('trialconfig', 1);
+%             end
+%             BA.dataCollectionFlag = 1;
+        end
+        function dataCollectionStop(obj)
+%             if obj.dataCollectionIsActive
+                disp('Data collection is now stopped.');
+                cbmex('trialconfig', 0);
+%             end
+%             obj.dataCollectionFlag = 0;
+        end
+%         function dataCollectionSetContActive(obj)
+%             disp('Continuous data collection is now active.');
+%             fprintf(2, 'Do not change any channel sampling frequency while continuous data collection is active.\n');
+%             obj.ContCollection = 1;
+%         end
+        function [spikeData, startTime, LFPData] = dataCollectionReadBuffer(obj)    
+            try
+                [spikeData, startTime, LFPData] = cbmex('trialdata', 1);
+            catch
+                fprintf(2,'Error...\n');
+                disp('Data collection is not active.');
+                disp('Use dataCollectionStart method to start locating.');
+            end
+%             if obj.contCollection
+%                 numChannelsRead = size(LFPData,1);
+%                 if isempty(obj.allLFPData)
+%                     obj.allLFPData = LFPData;
+%                 else
+%                     for idx = 1:numChannelsRead
+%                         obj.allLFPData{idx, 3} = [obj.allLFPData{idx, 3}; LFPData{idx, 3}];
+%                     end
+%                 end
+%             end
+        end
+%         function data = getDataLFPContinuous(obj)
+%             data = obj.allLFPData;
+%         end
+        
+        %% Detection Methods
+        function spikedChannels = detectChannelsFired(obj, units)
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            spikeData = dataCollectionReadBuffer(obj);
+            spikeData(:,1) = [];
+            spikedChannels = ~cellfun(@isempty, spikeData(:,units));
+        end
+        function fireFlag = detectChannelUnitFiredAny(obj, channels, units)
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            spikedChannels = obj.detectChannelsFired(units);
+            fireFlag = any(any(spikedChannels(channels, units)));
+        end
+        function fireFlag = detectChannelUnitFiredAll(obj, channels, units)
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            spikedChannels = obj.detectChannelsFired(units);
+            fireFlag = all(all(spikedChannels(channels, units)));
+        end
+        function fireFlag = detectWhenChannelUnitFiredAny(obj, channels, units, timeWindow)
+            fireFlag = 0;
+            if ~exist('units', 'var')
+                units = 1:5;
+            end
+            if ~exist('timeWindow', 'var')
+                timeWindow = 0.02;
+            end
+            while ~fireFlag
+                pause(timeWindow);
+                fireFlag = detectChannelUnitFiredAny(obj, channels, units);
+            end
+        end
+%         function fireFlag = detectWhenChannelUnitFiredAll(obj, channels, units, timeWindow)
+%             fireFlag = 0;
+%             if ~exist('units', 'var')
+%                 units = 1:5;
+%             end
+%             if ~exist('timeWindow', 'var')
+%                 timeWindow = 0.02;
+%             end
+%             while ~fireFlag
+%                 pause(timeWindow);
+%                 fireFlag = detectChannelUnitFiredAll(obj, channels, units);
+%             end
+%         end
+        function [bitValues, bitTimestamps] = detectDigInWord(obj)
+            readData = obj.dataCollectionReadBuffer;
+            bitValues = readData{151,3};
+            bitTimestamps = readData{151,2};
+        end
+        function [bitValues, bitTimestamps] = detectDigInBinary(obj)
+            readData = obj.dataCollectionReadBuffer;
+            bitValues = dec2bin(readData{151,3});
+            bitTimestamps = readData{151,2};
+        end
+% % % %         function fireFlag = detectDigInBit(obj, bitDetect)
+% % % %             fireFlag = 0;
+% % % %             if ~exist('bitDetect', 'var')
+% % % %                 disp('Please specify a bit that needs to be detected.');
+% % % %                 disp('Example: detectDigInBit(3)');
+% % % %                 return;
+% % % %             end
+% % % %             spikedChannels = obj.detectChannelsFired([1:5]);
+% % % %             if (bitDetect < 0) || (bitDetect > 15)
+% % % %                 disp('The bit value can be between 0 and 15, inclusive.');
+% % % %             else
+% % % %                 fireFlag = any(any(spikedChannels(136, 1:5)));
+% % % %             end
+% % % %         end
+        function fireFlag = detectWhenDigInWord(obj, wordValue, timeWindow)
+            fireFlag = 0;
+            if ~exist('wordValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('Please specify a word value that needs to be detected.');
+                disp('Example: detectDigInBit(128)');
+                return;
+            end
+            if ~exist('timeWindow', 'var')
+                timeWindow = 0.02;
+            end
+            while ~fireFlag
+                pause(timeWindow);
+                readWordValue = detectDigInWord(obj);
+                if wordValue == readWordValue
+                    fireFlag = 1;
+                end
+            end
+        end
+        function fireFlag = detectWhenDigInBit(obj, bitsValue, timeWindow)
+            fireFlag = 0;
+            if ~exist('bitValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('Please specify a bit pattern that needs to be detected.');
+                disp('Example: detectDigInBit(13)');
+                return;
+            end
+            if ~exist('timeWindow', 'var')
+                timeWindow = 0.02;
+            end
+            while ~fireFlag
+                pause(timeWindow);
+                bitsValue = detectDigInBit(obj, bitDetect);
+                if strcmpi(bitsValue, readWordValue)
+                    fireFlag = 1;
+                end
+            end
+        end
+        
+        %% Get Configuration Values
+        function configValue = getAllChannelLabels(obj)
+            configStream = cbmex('chanlabel');
+            configValue = configStream(:,1);
+        end
+        function configValue = getChannelLabel(obj, channel)
+            configStream = cbmex('chanlabel', channel);
+            configValue = configStream{1};
+        end
+        function isFlag = isChannelSpikeExtractionEnabled(obj, channel)
+            configStream = cbmex('chanlabel', channel);
+            isFlag = configStream{2};
+        end
+        function isFlag = isChannelUnitEnabled(obj, channel, unit)
+            configStream = cbmex('chanlabel', channel);
+            isFlag = configStream{unit};
+        end
+        function ampRejRange = getAmplitudeRejectionRange(obj, channel)
+            configStream = cbmex('config', channel);
+            ampRejRange = [configStream{12,2}, configStream{13,2}];               
+        end
+        function setAmplitudeRejectionRange(obj, channel, newValue)
+            if ~exist('newValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('newValue is a required argument.');
+                return;
+            end
+            if length(newValue)<2 || length(newValue)>2
+                fprintf(2,'Error...\n');
+                disp('The passed argument to this function should have two values: lower and higher amplitude rejection values, respectively.');
+                return;
+            end
+            if newValue(1)>=newValue(2)
+                fprintf(2,'Error...\n');
+                disp('The low amplitude rejection value should be smaller than the high value.');
+                return;
+            end
+            configStream = cbmex('config', channel, 'amplrejneg', newValue(1));
+            configStream = cbmex('config', channel, 'amplrejpos', newValue(2));          
+        end       
+        function spikeThresh = getSpikeThresholdValue(obj, channel)
+            configStream = cbmex('config', channel);
+            spikeThresh = ceil(configStream{10, 2}/4);
+        end
+        function setSpikeThresholdValue(obj, channel, newValue)
+            if ~exist('newValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('newValue is a required argument.');
+                return;
+            else
+                configStream = cbmex('config', channel, 'spkthrlevel', newValue * 4);
+            end
+        end
+        function refChan = getDigitalReferenceChannel(obj, channel)
+            configStream = cbmex('config', channel);
+            refChan = configStream{14,2};
+        end
+        function refChan = setDigitalReferenceChannel(obj, channel, newValue)
+            if ~exist('newValue', 'var')
+                fprintf(2,'Error...\n');
+                disp('newValue is a required argument.');
+                return;
+            else
+                configStream = cbmex('config', channel, 'refelecchan', newValue);
+            end
+        end
+        
+        %% Data Analysis Methods
+        function onlineSpectogram(obj, frequencyRange)
+            if ~exist('frequencyRange', 'var')
+                fprintf(2,'Error...\n');
+                disp('You need to define a frequency range for this function.');
+                disp('Example: onlineSpectrogram([0.3, 7500]) to show the spectrogram in the range of 0.3 Hz to 7500 Hz.');
+                return;
+            end
+            frequencyRange = linspace(frequencyRange(1), frequencyRange(end), 150);
+            % All durations are in second
+            sampleCollectionDuration = 0.02;
+            refreshRate = 0.05;
+            % Setting up a default frequency range, if none is specified
+            if ~exist('frequencyRange', 'var')
+                disp('Frequency range was not specified. A default range of 0.3:1:7500 will be used.');
+                frequencyRange = 0.3:1:7500;
+            end
+            % Setting up the figure
+            procFigure = figure;
+            set(procFigure, 'Name', 'Close this figure to stop'); 
+            % Setting up collection variable
+            timeDisplay = tic;
+            timeCollection = tic;
+            flagCollection = 1;
+            % Collection
+            dataCollectionStart(obj);
+            while ishandle(procFigure)
+                pause(0.001);
+                if flagCollection
+                    timeCollectionET = toc(timeCollection);
+                    if timeCollectionET > sampleCollectionDuration
+                        [spikeData, startTime, contData] = dataCollectionReadBuffer(obj);
+                        nGraphs = size(contData,1);
+                        if ishandle(procFigure)
+                            for idx = 1:nGraphs
+                                fs0 = contData{idx, 2};
+                                data = contData{idx, 3};
+                                collectSize = min(size(data), sampleCollectionDuration * fs0);
+                                x = data(1:collectSize);
+                                if isempty(frequencyRange)
+                                    [psd, f] = periodogram(double(x),[],'onesided',512,fs0); 
+                                else
+                                    [psd, f] = periodogram(double(x),[],frequencyRange,fs0);
+                                end
+                                subplot(nGraphs,1,idx,'Parent',procFigure);
+                                psdLog = 10*log10(psd);
+                                plot(f, psdLog, 'b');
+                                title(sprintf('fs = %d t = %f',fs0, startTime));
+                                xlabel('Frequency (Hz)'); xlim([frequencyRange(1), frequencyRange(end)]);
+                                ylabel('Magnitude (dB)');
+                            end
+                            drawnow;
+                        end
+                        flagCollection = 0;
+                    end
+                end
+                timeCollectionET = toc(timeDisplay);
+                if timeCollectionET >= refreshRate;
+                    timeDisplay = tic;
+                    timeCollection = tic;
+                    flagCollection = 1;
+                end
+            end
+            dataCollectionStop(obj);
+        end       
+    end
+end

+ 11 - 0
code/matlab_scripts/NPMK/@KTUEAImpedanceFile/.svn/all-wcprops

@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 45
+/svnroot/npmk/!svn/ver/28/@KTUEAImpedanceFile
+END
+KTUEAImpedanceFile.m
+K 25
+svn:wc:ra_dav:version-url
+V 66
+/svnroot/npmk/!svn/ver/28/@KTUEAImpedanceFile/KTUEAImpedanceFile.m
+END

+ 62 - 0
code/matlab_scripts/NPMK/@KTUEAImpedanceFile/.svn/entries

@@ -0,0 +1,62 @@
+10
+
+dir
+42
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/@KTUEAImpedanceFile
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2011-04-04T18:37:20.186713Z
+28
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+KTUEAImpedanceFile.m
+file
+
+
+
+
+2011-10-27T11:57:48.000000Z
+99041615af9e89a38cec95b0b8a61cb1
+2011-04-04T18:37:20.186713Z
+28
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+11510
+

+ 249 - 0
code/matlab_scripts/NPMK/@KTUEAImpedanceFile/.svn/text-base/KTUEAImpedanceFile.m.svn-base

@@ -0,0 +1,249 @@
+classdef KTUEAImpedanceFile
+
+% Plots a graphical representation of the impedance data collected by
+% Cerebus and saved in a text file.
+%
+% Usage:
+%
+%   plotImpedances(mapfile)
+%
+%   WHERE:
+%
+%   mapfile:    Is the mapfile structure obtained with mapfileLoader
+%               function that maps the electrodes to channel numbers. If
+%               mapfile is not provided then a default map will be used.
+%
+%   To see a list of methods type methods(plotImpedances).
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.1.0
+%
+%   Ideas borrowed from Sergey Stavisky, The BrainGate Project
+
+    properties (Hidden, SetAccess = private, GetAccess = private)
+        chanCount    = 96;
+        impedanceDataValues = NaN(1, 96);
+        Mapfile
+        fileHandle
+        pathHandle
+    end
+    methods(Hidden)
+        function obj = KTUEAImpedanceFile(Mapfile)
+            if ~exist('Mapfile', 'var')
+                obj.Mapfile = KTUEAMapFile;
+            else
+                obj.Mapfile = Mapfile;
+            end
+            if ~obj.Mapfile.isValid; return; end;
+            
+            if exist('getFile.m', 'file') == 2
+                [obj.fileHandle obj.pathHandle] = getFile('*.txt', 'Open an impedance file...');
+            else
+                [obj.fileHandle obj.pathHandle] = uigetfile('*.txt', 'Open an impedance file...');
+            end
+            if ~obj.fileHandle; disp('No file was selected.'); return; end;
+            impedanceDataCell = importdata([obj.pathHandle obj.fileHandle], ' ', 200);
+            impedanceDataCell(1:9) = [];
+            impedanceDataCell(97:end) = [];
+            impedanceDataCellParsed = regexp(impedanceDataCell, '\t', 'split');
+            for i = 1:size(impedanceDataCellParsed, 1)
+                impedanceSingleCell = impedanceDataCellParsed{i,:}(2);
+                impedanceSingleText = impedanceSingleCell{:};
+                obj.impedanceDataValues(i) = str2double(impedanceSingleText(1:end-4));
+            end
+        end
+    end
+    methods
+        function FilePath = PathName(obj)
+            FilePath = obj.pathHandle;
+        end
+        function FileName = Filename(obj)
+            FileName = obj.fileHandle;
+        end
+        function validFlag = isValid(obj)
+            if any(isnan(obj.getChannelImpedances)) 
+                validFlag = 0;
+            else
+                validFlag = 1;
+            end
+        end
+        function impedanceDataValues = getImpedances(obj)
+            impedanceDataValues = obj.impedanceDataValues;
+        end
+        function impedanceDataValue = getChannelImpedance(obj, chanNum)
+            if ~exist('chanNum', 'var')
+                disp('Channel number is a required argument.');
+                return;
+            end
+            impedanceDataValue = obj.impedanceDataValues(chanNum);
+        end
+        function analyzedStat = getImpedanceMean(obj)
+            analyzedStat = mean(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedanceMedian(obj)
+            analyzedStat = median(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedanceRange(obj)
+            analyzedStat = obj.getImpedanceMax-obj.getImpedanceMin;
+        end
+        function analyzedStat = getImpedanceSTD(obj)
+            analyzedStat = std(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedance975Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.975));
+        end
+        function analyzedStat = getImpedance750Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.75));
+        end
+        function analyzedStat = getImpedance250Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.25));
+        end
+        function analyzedStat = getImpedance25Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.025));
+        end
+        function analyzedStat = getImpedanceMin(obj)
+            analyzedStat = min(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedanceMax(obj)
+            analyzedStat = max(obj.impedanceDataValues);
+        end
+        function plotStatistics(obj)
+            figure('Name', 'Array Statistics');
+            title('Array Impedance Values Statistics');
+            set(gcf, 'Position', [657 540 288 287]);
+            axis off;
+            text(0,0.9, 'Mean');                                                                                                             text(0.6,0.9, num2str(obj.getImpedanceMean, '%5.1f'));
+            text(0,0.8, 'Median');            text(0.6,0.8, num2str(obj.getImpedanceMean, '%5.1f'));
+            text(0,0.7, 'Range');             text(0.6,0.7, num2str(obj.getImpedanceRange, '%5.1f'));
+            text(0,0.6, 'STD');               text(0.6,0.6, num2str(obj.getImpedanceSTD, '%5.1f'));
+            text(0,0.5, '97.5th Percentile'); text(0.6,0.5, num2str(obj.getImpedance975Perc, '%5.1f'));
+            text(0,0.4, '75th Percentile');   text(0.6,0.4, num2str(obj.getImpedance750Perc, '%5.1f'));
+            text(0,0.3, '25th Percentile');   text(0.6,0.3, num2str(obj.getImpedance250Perc, '%5.1f'));
+            text(0,0.2, '2.5th Percentile');  text(0.6,0.2, num2str(obj.getImpedance25Perc, '%5.1f'));
+            text(0,0.1, 'Min');               text(0.6,0.1, num2str(obj.getImpedanceMin, '%5.1f'));
+            text(0,0.0, 'Max');               text(0.6,0.0, num2str(obj.getImpedanceMax, '%5.1f'));
+        end
+        function plotHistogram(obj, binCount, maxRange)
+            if ~exist('binCount', 'var')
+                binCount = 20;
+            end
+            if ~exist('maxRange', 'var')
+                if max(obj.impedanceDataValues) > 10000
+                    maxRange = 10000;
+                else
+                    maxRange = max(obj.impedanceDataValues);
+                end
+            end
+            hist(obj.impedanceDataValues, min(obj.impedanceDataValues):...
+                                          maxRange/binCount:...
+                                          maxRange,1);
+        title('Impedance Values Histogram');
+        xlabel('Impedance Values (kOhm)');
+        ylabel('Impedance Occurances');
+        end
+        function plotBoxPlot(obj, boxStyle)
+            if ~exist('boxStyle', 'var');
+                boxStyle = 'traditional';
+            end
+            sortedImpedances = sort(obj.impedanceDataValues);
+
+            boxplot(obj.impedanceDataValues);
+            title(['Box Plot (' boxStyle ')']);
+            ylabel('Impedance Values (kOhm)');
+            set(gca, 'xTickLabel', ' ');
+            xlim([0.9, 1.1]);
+            set(gcf, 'Position', [632 356 235 398]);             
+        end
+        function plotImpedances(obj, yelThreshold, redThreshold)
+            if ~exist('yelThreshold', 'var')
+                yelThreshold = 100;
+            end
+            if ~exist('redThreshold', 'var')
+                redThreshold = 800;
+            end
+            plotFigure = KTFigure;
+            plotFigure.EnlargeFigure;
+            plotFigure.MakeBackgroundWhite;
+            hold on;
+            for channelIDX = 1:obj.chanCount
+                if obj.impedanceDataValues(channelIDX) > redThreshold
+                    spColor = [1,0,0];
+                    fColor  = [1,1,1];
+                elseif obj.impedanceDataValues(channelIDX) < redThreshold && obj.impedanceDataValues(channelIDX) > yelThreshold
+                    spColor = [0,0,0];
+                    fColor  = [1,1,1];
+                elseif obj.impedanceDataValues(channelIDX) < yelThreshold
+                    spColor = [1,1,0];
+                    fColor  = [0,0,0];
+                end
+                obj.Mapfile.GenerateChannelSubplot(channelIDX);
+                obj.Mapfile.GenerateChannelSubplotNames(channelIDX, fColor);
+                text(0.05, 0.7, [num2str(obj.impedanceDataValues(channelIDX)) ' kOhm'], 'Color', fColor, 'FontSize', 10, 'FontWeight', 'bold');
+                axis on;
+                obj.Mapfile.setAxisBackgroundColor(spColor);
+                obj.Mapfile.setAxesColor(spColor);
+            end
+            hold off;
+            plotFigure.ShowFigure;
+        end
+        function plotImpedancesColorBackground(obj)
+            for channelIDX = 1:obj.chanCount
+                obj.Mapfile.GenerateChannelSubplot(channelIDX);
+                axis on;
+                obj.Mapfile.setAxisBackgroundColor([0,obj.impedanceDataValues(channelIDX)/max(max(obj.impedanceDataValues)),0]);        
+            end
+        end
+        function plotImpedancesComparison(obj)
+            changeThreshold = 0.2;
+            yelThreshold = 100;
+            secImpedanceFile = KTUEAImpedanceFile(obj.Mapfile);
+            secImpedanceValues = secImpedanceFile.getChannelImpedances;
+            plotFigure = KTFigure;
+            plotFigure.EnlargeFigure;
+            plotFigure.MakeBackgroundWhite;
+            hold on;
+            for channelIDX = 1:obj.chanCount
+                percentChange = (obj.impedanceDataValues(channelIDX) - secImpedanceValues(channelIDX))/obj.impedanceDataValues(channelIDX);
+                if abs(percentChange)  > changeThreshold && percentChange > 0
+                    % Lime Green -- If impedance is increased by more 
+                    % than threshold.
+                    if abs(percentChange) > 2 * changeThreshold
+                        spColor = [34,139,34] ./255;
+                        fColor  = [1,1,1];
+                    else
+                        spColor = [154,205,50] ./255;
+                        fColor  = [0,0,0];
+                    end
+                elseif abs(percentChange) > changeThreshold && percentChange < 0
+                    % Chocolate orange -- If impedance is dropped by more 
+                    % than threshold.
+                    if abs(percentChange) > 2 * changeThreshold
+                        spColor = [210,105,30] ./255;
+                        fColor  = [1,1,1];
+                    else
+                        spColor = [245,222,179] ./255;
+                        fColor  = [0,0,0];
+                    end
+                else
+                    % Honeydew -- If threshold change is less than
+                    % threshold.
+                    spColor = [240,255,240] ./255;
+                    fColor  = [0,0,0];
+                end
+                obj.Mapfile.GenerateChannelSubplot(channelIDX);
+                patchHandle = patch([0.5, 0.5, 0, 0], [1, 0, 0, 1], spColor);
+                obj.Mapfile.GenerateChannelSubplotNames(channelIDX, fColor);
+                text(0.05, 0.7, ['1: ' num2str(obj.impedanceDataValues(channelIDX)) ' kOhm'], 'Color', fColor, 'FontSize', 10, 'FontWeight', 'bold');
+                text(0.05, 0.5, ['2: ' num2str(secImpedanceValues(channelIDX)) ' kOhm'], 'Color', fColor, 'FontSize', 10, 'FontWeight', 'bold');
+            end
+            hold off;
+            plotFigure.ShowFigure;
+        end
+    end
+end

+ 249 - 0
code/matlab_scripts/NPMK/@KTUEAImpedanceFile/KTUEAImpedanceFile.m

@@ -0,0 +1,249 @@
+classdef KTUEAImpedanceFile
+
+% Plots a graphical representation of the impedance data collected by
+% Cerebus and saved in a text file.
+%
+% Usage:
+%
+%   plotImpedances(mapfile)
+%
+%   WHERE:
+%
+%   mapfile:    Is the mapfile structure obtained with mapfileLoader
+%               function that maps the electrodes to channel numbers. If
+%               mapfile is not provided then a default map will be used.
+%
+%   To see a list of methods type methods(plotImpedances).
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.1.0
+%
+%   Ideas borrowed from Sergey Stavisky, The BrainGate Project
+
+    properties (Hidden, SetAccess = private, GetAccess = private)
+        chanCount    = 96;
+        impedanceDataValues = NaN(1, 96);
+        Mapfile
+        fileHandle
+        pathHandle
+    end
+    methods(Hidden)
+        function obj = KTUEAImpedanceFile(Mapfile)
+            if ~exist('Mapfile', 'var')
+                obj.Mapfile = KTUEAMapFile;
+            else
+                obj.Mapfile = Mapfile;
+            end
+            if ~obj.Mapfile.isValid; return; end;
+            
+            if exist('getFile.m', 'file') == 2
+                [obj.fileHandle obj.pathHandle] = getFile('*.txt', 'Open an impedance file...');
+            else
+                [obj.fileHandle obj.pathHandle] = uigetfile('*.txt', 'Open an impedance file...');
+            end
+            if ~obj.fileHandle; disp('No file was selected.'); return; end;
+            impedanceDataCell = importdata([obj.pathHandle obj.fileHandle], ' ', 200);
+            impedanceDataCell(1:9) = [];
+            impedanceDataCell(97:end) = [];
+            impedanceDataCellParsed = regexp(impedanceDataCell, '\t', 'split');
+            for i = 1:size(impedanceDataCellParsed, 1)
+                impedanceSingleCell = impedanceDataCellParsed{i,:}(2);
+                impedanceSingleText = impedanceSingleCell{:};
+                obj.impedanceDataValues(i) = str2double(impedanceSingleText(1:end-4));
+            end
+        end
+    end
+    methods
+        function FilePath = PathName(obj)
+            FilePath = obj.pathHandle;
+        end
+        function FileName = Filename(obj)
+            FileName = obj.fileHandle;
+        end
+        function validFlag = isValid(obj)
+            if any(isnan(obj.getChannelImpedances)) 
+                validFlag = 0;
+            else
+                validFlag = 1;
+            end
+        end
+        function impedanceDataValues = getImpedances(obj)
+            impedanceDataValues = obj.impedanceDataValues;
+        end
+        function impedanceDataValue = getChannelImpedance(obj, chanNum)
+            if ~exist('chanNum', 'var')
+                disp('Channel number is a required argument.');
+                return;
+            end
+            impedanceDataValue = obj.impedanceDataValues(chanNum);
+        end
+        function analyzedStat = getImpedanceMean(obj)
+            analyzedStat = mean(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedanceMedian(obj)
+            analyzedStat = median(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedanceRange(obj)
+            analyzedStat = obj.getImpedanceMax-obj.getImpedanceMin;
+        end
+        function analyzedStat = getImpedanceSTD(obj)
+            analyzedStat = std(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedance975Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.975));
+        end
+        function analyzedStat = getImpedance750Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.75));
+        end
+        function analyzedStat = getImpedance250Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.25));
+        end
+        function analyzedStat = getImpedance25Perc(obj)
+            sortedImpedances = sort(obj.impedanceDataValues, 'ascend');
+            analyzedStat = sortedImpedances(round(obj.chanCount*0.025));
+        end
+        function analyzedStat = getImpedanceMin(obj)
+            analyzedStat = min(obj.impedanceDataValues);
+        end
+        function analyzedStat = getImpedanceMax(obj)
+            analyzedStat = max(obj.impedanceDataValues);
+        end
+        function plotStatistics(obj)
+            figure('Name', 'Array Statistics');
+            title('Array Impedance Values Statistics');
+            set(gcf, 'Position', [657 540 288 287]);
+            axis off;
+            text(0,0.9, 'Mean');                                                                                                             text(0.6,0.9, num2str(obj.getImpedanceMean, '%5.1f'));
+            text(0,0.8, 'Median');            text(0.6,0.8, num2str(obj.getImpedanceMean, '%5.1f'));
+            text(0,0.7, 'Range');             text(0.6,0.7, num2str(obj.getImpedanceRange, '%5.1f'));
+            text(0,0.6, 'STD');               text(0.6,0.6, num2str(obj.getImpedanceSTD, '%5.1f'));
+            text(0,0.5, '97.5th Percentile'); text(0.6,0.5, num2str(obj.getImpedance975Perc, '%5.1f'));
+            text(0,0.4, '75th Percentile');   text(0.6,0.4, num2str(obj.getImpedance750Perc, '%5.1f'));
+            text(0,0.3, '25th Percentile');   text(0.6,0.3, num2str(obj.getImpedance250Perc, '%5.1f'));
+            text(0,0.2, '2.5th Percentile');  text(0.6,0.2, num2str(obj.getImpedance25Perc, '%5.1f'));
+            text(0,0.1, 'Min');               text(0.6,0.1, num2str(obj.getImpedanceMin, '%5.1f'));
+            text(0,0.0, 'Max');               text(0.6,0.0, num2str(obj.getImpedanceMax, '%5.1f'));
+        end
+        function plotHistogram(obj, binCount, maxRange)
+            if ~exist('binCount', 'var')
+                binCount = 20;
+            end
+            if ~exist('maxRange', 'var')
+                if max(obj.impedanceDataValues) > 10000
+                    maxRange = 10000;
+                else
+                    maxRange = max(obj.impedanceDataValues);
+                end
+            end
+            hist(obj.impedanceDataValues, min(obj.impedanceDataValues):...
+                                          maxRange/binCount:...
+                                          maxRange,1);
+        title('Impedance Values Histogram');
+        xlabel('Impedance Values (kOhm)');
+        ylabel('Impedance Occurances');
+        end
+        function plotBoxPlot(obj, boxStyle)
+            if ~exist('boxStyle', 'var');
+                boxStyle = 'traditional';
+            end
+            sortedImpedances = sort(obj.impedanceDataValues);
+
+            boxplot(obj.impedanceDataValues);
+            title(['Box Plot (' boxStyle ')']);
+            ylabel('Impedance Values (kOhm)');
+            set(gca, 'xTickLabel', ' ');
+            xlim([0.9, 1.1]);
+            set(gcf, 'Position', [632 356 235 398]);             
+        end
+        function plotImpedances(obj, yelThreshold, redThreshold)
+            if ~exist('yelThreshold', 'var')
+                yelThreshold = 100;
+            end
+            if ~exist('redThreshold', 'var')
+                redThreshold = 800;
+            end
+            plotFigure = KTFigure;
+            plotFigure.EnlargeFigure;
+            plotFigure.MakeBackgroundWhite;
+            hold on;
+            for channelIDX = 1:obj.chanCount
+                if obj.impedanceDataValues(channelIDX) > redThreshold
+                    spColor = [1,0,0];
+                    fColor  = [1,1,1];
+                elseif obj.impedanceDataValues(channelIDX) < redThreshold && obj.impedanceDataValues(channelIDX) > yelThreshold
+                    spColor = [0,0,0];
+                    fColor  = [1,1,1];
+                elseif obj.impedanceDataValues(channelIDX) < yelThreshold
+                    spColor = [1,1,0];
+                    fColor  = [0,0,0];
+                end
+                obj.Mapfile.GenerateChannelSubplot(channelIDX);
+                obj.Mapfile.GenerateChannelSubplotNames(channelIDX, fColor);
+                text(0.05, 0.7, [num2str(obj.impedanceDataValues(channelIDX)) ' kOhm'], 'Color', fColor, 'FontSize', 10, 'FontWeight', 'bold');
+                axis on;
+                obj.Mapfile.setAxisBackgroundColor(spColor);
+                obj.Mapfile.setAxesColor(spColor);
+            end
+            hold off;
+            plotFigure.ShowFigure;
+        end
+        function plotImpedancesColorBackground(obj)
+            for channelIDX = 1:obj.chanCount
+                obj.Mapfile.GenerateChannelSubplot(channelIDX);
+                axis on;
+                obj.Mapfile.setAxisBackgroundColor([0,obj.impedanceDataValues(channelIDX)/max(max(obj.impedanceDataValues)),0]);        
+            end
+        end
+        function plotImpedancesComparison(obj)
+            changeThreshold = 0.2;
+            yelThreshold = 100;
+            secImpedanceFile = KTUEAImpedanceFile(obj.Mapfile);
+            secImpedanceValues = secImpedanceFile.getChannelImpedances;
+            plotFigure = KTFigure;
+            plotFigure.EnlargeFigure;
+            plotFigure.MakeBackgroundWhite;
+            hold on;
+            for channelIDX = 1:obj.chanCount
+                percentChange = (obj.impedanceDataValues(channelIDX) - secImpedanceValues(channelIDX))/obj.impedanceDataValues(channelIDX);
+                if abs(percentChange)  > changeThreshold && percentChange > 0
+                    % Lime Green -- If impedance is increased by more 
+                    % than threshold.
+                    if abs(percentChange) > 2 * changeThreshold
+                        spColor = [34,139,34] ./255;
+                        fColor  = [1,1,1];
+                    else
+                        spColor = [154,205,50] ./255;
+                        fColor  = [0,0,0];
+                    end
+                elseif abs(percentChange) > changeThreshold && percentChange < 0
+                    % Chocolate orange -- If impedance is dropped by more 
+                    % than threshold.
+                    if abs(percentChange) > 2 * changeThreshold
+                        spColor = [210,105,30] ./255;
+                        fColor  = [1,1,1];
+                    else
+                        spColor = [245,222,179] ./255;
+                        fColor  = [0,0,0];
+                    end
+                else
+                    % Honeydew -- If threshold change is less than
+                    % threshold.
+                    spColor = [240,255,240] ./255;
+                    fColor  = [0,0,0];
+                end
+                obj.Mapfile.GenerateChannelSubplot(channelIDX);
+                patchHandle = patch([0.5, 0.5, 0, 0], [1, 0, 0, 1], spColor);
+                obj.Mapfile.GenerateChannelSubplotNames(channelIDX, fColor);
+                text(0.05, 0.7, ['1: ' num2str(obj.impedanceDataValues(channelIDX)) ' kOhm'], 'Color', fColor, 'FontSize', 10, 'FontWeight', 'bold');
+                text(0.05, 0.5, ['2: ' num2str(secImpedanceValues(channelIDX)) ' kOhm'], 'Color', fColor, 'FontSize', 10, 'FontWeight', 'bold');
+            end
+            hold off;
+            plotFigure.ShowFigure;
+        end
+    end
+end

+ 11 - 0
code/matlab_scripts/NPMK/@KTUEAMapFile/.svn/all-wcprops

@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svnroot/npmk/!svn/ver/23/@KTUEAMapFile
+END
+KTUEAMapFile.m
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svnroot/npmk/!svn/ver/52/@KTUEAMapFile/KTUEAMapFile.m
+END

+ 62 - 0
code/matlab_scripts/NPMK/@KTUEAMapFile/.svn/entries

@@ -0,0 +1,62 @@
+10
+
+dir
+42
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/@KTUEAMapFile
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2011-03-03T23:50:24.982281Z
+23
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+KTUEAMapFile.m
+file
+52
+
+
+
+2011-12-15T09:00:23.000000Z
+16768f4f955aae2358290461af25039e
+2012-03-27T23:48:00.007201Z
+52
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10770
+

+ 256 - 0
code/matlab_scripts/NPMK/@KTUEAMapFile/.svn/text-base/KTUEAMapFile.m.svn-base

@@ -0,0 +1,256 @@
+classdef KTUEAMapFile
+
+% UEAMAPFILE -- Defines a class that contains information on a UEA
+% electrode array using CMP files provided by Blackrock Microsystems.
+%
+% To load a CMP file type 'MapName = UEAMapFile' where MapName is the name
+% of the variable that will be created and will contain the map class.
+%
+% Example: myArrayMap = UEAMapFile;
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% METHODS:
+%
+% There are several available methods for mapfiles. Here's a list and a
+% description of what they perform.
+%
+% Electrode2Channel(Electrode): 
+%   Will return the Channel number corresponding to a passed Electrode.
+%
+% Channel2Electrode(Channel):   
+%   Will return the Electrode number corresponding to a passed Channel.
+%
+% GetChannelBankID(Channel):
+%   Returns the BankID for a passed Channel.
+%
+% GetChannelPin(Channel):
+%   Returns the Pin for a passed Channel.
+%
+% GetChannelLabel(Channel):
+%   Returns the Label for a passed Channel.
+%
+% GenerateChannelSubplot(Channel):
+%   Returns a subplot handle for the passed Channel to be used in plotting
+%   UEA-like maps.
+%
+% GenerateChannelSubplotNames(Channel):
+%   Plots the names of channels and electrodes on the subplot corresponding
+%   to the passed Channel.
+%
+% GetChannelColumnRow(Channel):
+%   Returns the Column and Row positions of the passed number that is used
+%   to plot UEA-like maps.
+%
+% PlotCMP:
+%   Will plot a map of the CMP Map with all the electrode and channel
+%   names.
+%
+%   Kian Torab
+%   Blackrock Microsystems
+%   ktorab@blackrockmicro.com
+%
+%   Version 1.5
+
+
+%%
+    properties (SetAccess = private)
+        ElecNum
+        ChanNum
+        Column
+        Row
+        Bank
+        Pin
+        Label
+        pathHandle
+        fileHandle
+    end
+    methods (Hidden)
+        function obj = KTUEAMapFile(fileName)
+            if ~exist('fileName', 'var')
+                if exist('getFile.m', 'file') == 2
+                    [obj.fileHandle obj.pathHandle] = getFile('*.cmp', 'Open a CMP Mapfile...');
+                else
+                    [obj.fileHandle obj.pathHandle] = uigetfile('*.cmp', 'Open a CMP Mapfile...');
+                end
+                if ~obj.fileHandle
+                    disp('No file was selected.'); 
+                    return; 
+                end
+                mapfileDataCell = importdata([obj.pathHandle obj.fileHandle], ' ', 200);
+            else
+                mapfileDataCell = importdata(fileName, ' ', 200);
+            end
+            lastJunkIDX = find(~cellfun(@isempty, strfind(mapfileDataCell, '//')) == 1, 1, 'last') + 1;
+            mapfileDataCell(1:lastJunkIDX) = [];
+            mapfileDataCellParsed = regexp(mapfileDataCell, '\t', 'split');
+            if size(mapfileDataCellParsed, 2) == 1
+                mapfileDataCellParsed = regexp(mapfileDataCell, '\s+', 'split');
+            end
+            for i = 1:size(mapfileDataCellParsed, 1)
+                if ~all(isspace(mapfileDataCell{i}))
+                    obj.Column(i) = str2num(mapfileDataCellParsed{i,:}{1});
+                    obj.Row(i)    = str2num(mapfileDataCellParsed{i,:}{2});
+                    obj.Bank(i)   = mapfileDataCellParsed{i,:}{3}-'@';
+                    obj.Pin(i)    = str2num(mapfileDataCellParsed{i,:}{4});
+                    ElectNum      = str2num(mapfileDataCellParsed{i,:}{5}(5:end));
+                    if isempty(ElectNum)
+                        obj.ElecNum(i) = str2num(mapfileDataCellParsed{i,:}{5}(2:end-4));
+                    else
+                        obj.ElecNum(i) = ElectNum;
+                    end
+                    obj.ChanNum(i)  = (obj.Bank(i) - 1) * 32 + obj.Pin(i);
+                    obj.Label{i}    = mapfileDataCellParsed{i,:}{5};
+                end
+            end
+        end
+    end
+    methods
+        function validFlag = isValid(obj)
+            if ~obj.getFilename
+                validFlag = 0;
+            else
+                validFlag = 1;
+            end
+        end
+        function FilePath = getPathName(obj)
+            FilePath = obj.pathHandle;
+        end
+        function FileName = getFilename(obj)
+            FileName = obj.fileHandle;
+        end
+        function Channel = Electrode2Channel(obj, Electrode)
+            if ~exist('Electrode', 'var'); disp('Electrode is a required input. Refer to help for more information.'); return; end;
+            if isempty(obj.ChanNum(obj.ElecNum == Electrode(1)))
+                disp('Electrode number is invalid.');
+                Channel = [];
+                return;
+            end
+            for ElecIDX = 1:length(Electrode)
+                Channel(ElecIDX) = obj.ChanNum(obj.ElecNum == Electrode(ElecIDX));
+            end
+        end
+        function Electrode = Channel2Electrode(obj, Channel)
+            if isempty(obj.ElecNum(obj.ChanNum == Channel(1)))
+                disp('Channel number is invalid.');
+                Electrode = [];
+                return;
+            end            
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            for ChanIDX = 1:length(Channel)
+                Electrode(ChanIDX) = obj.ElecNum(obj.ChanNum == Channel(ChanIDX));
+            end
+        end
+        function BankID = getChannelBankID(obj, Channel)
+            BankID = obj.Bank(obj.ChanNum == Channel);
+        end
+        function Label = getChannelLabel(obj, Channel)
+            Label = char(obj.Label{obj.ChanNum == Channel});
+        end
+        function Pin = getChannelPin(obj, Channel)
+            Pin = obj.Pin(obj.ChanNum == Channel);
+        end
+        function spHandle = GenerateChannelSubplot(obj, Channel)
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            [x, y] = getChannelColumnRow(obj, Channel);
+            spHandle=subplot('position', [x/10+0.004, y/10+0.004, 1/10-0.004, 1/10-0.004]);
+            axis off;
+            box on;
+            set(spHandle,'XTickLabel', []);
+            set(spHandle,'YTickLabel', []);
+            %%
+        end
+        function GenerateChannelSubplotNames(obj, Channel, fColor)
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            if ~exist('fColor', 'var'); fColor  = [1,1,1]; end
+            Electrode = Channel2Electrode(obj, Channel);
+            text(0.13, 0.23, ['elec ', num2str(Electrode)], 'Color', fColor, 'FontSize', 8);
+            text(0.13, 0.10, ['chan ', num2str(Channel)], 'Color', fColor, 'FontSize', 8);            
+        end
+        function [x, y] = getChannelColumnRow(obj, Channel)
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            x = obj.Column(obj.ChanNum == Channel);
+            y = obj.Row(obj.ChanNum == Channel);
+        end
+        function PlotCMP(obj)
+            figure;
+            for Channel = 1:96
+                GenerateChannelSubplot(obj, Channel);
+                GenerateChannelSubplotNames(obj, Channel, [0,0,0]);
+            end
+        end
+        function setAxisBackgroundColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'Color', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                	set(gca, 'Color', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end
+        function setXAxisColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'XColor', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                    set(gca, 'XColor', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end
+        function setYAxisColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'YColor', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                    set(gca, 'YColor', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end
+        function setAxesColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'YColor', curColor);
+                    set(gca, 'XColor', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                    set(gca, 'YColor', curColor);
+                    set(gca, 'XColor', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end        
+    end
+end

+ 277 - 0
code/matlab_scripts/NPMK/@KTUEAMapFile/KTUEAMapFile.m

@@ -0,0 +1,277 @@
+classdef KTUEAMapFile
+
+% UEAMAPFILE -- Defines a class that contains information on a UEA
+% electrode array using CMP files provided by Blackrock Microsystems.
+%
+% To load a CMP file type 'MapName = UEAMapFile' where MapName is the name
+% of the variable that will be created and will contain the map class.
+%
+% Example: myArrayMap = UEAMapFile;
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% METHODS:
+%
+% There are several available methods for mapfiles. Here's a list and a
+% description of what they perform.
+%
+% Electrode2Channel(Electrode): 
+%   Will return the Channel number corresponding to a passed Electrode.
+%
+% Channel2Electrode(Channel):   
+%   Will return the Electrode number corresponding to a passed Channel.
+%
+% GetChannelBankID(Channel):
+%   Returns the BankID for a passed Channel.
+%
+% GetChannelPin(Channel):
+%   Returns the Pin for a passed Channel.
+%
+% GetChannelLabel(Channel):
+%   Returns the Label for a passed Channel.
+%
+% GenerateChannelSubplot(Channel):
+%   Returns a subplot handle for the passed Channel to be used in plotting
+%   UEA-like maps.
+%
+% GenerateChannelSubplotNames(Channel):
+%   Plots the names of channels and electrodes on the subplot corresponding
+%   to the passed Channel.
+%
+% GetChannelColumnRow(Channel):
+%   Returns the Column and Row positions of the passed number that is used
+%   to plot UEA-like maps.
+%
+% PlotCMP:
+%   Will plot a map of the CMP Map with all the electrode and channel
+%   names.
+%
+%   Kian Torab
+%   Blackrock Microsystems
+%   ktorab@blackrockmicro.com
+%
+%   Version 1.6.1.0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 1.6.1.0:
+%   - Minor bug fix.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%
+    properties (SetAccess = private)
+        ElecNum
+        ChanNum
+        Column
+        Row
+        Bank
+        Pin
+        Label
+        pathHandle
+        fileHandle
+    end
+    methods (Hidden)
+        function obj = KTUEAMapFile(fileName)
+            if ~exist('fileName', 'var')
+                if exist('getFile.m', 'file') == 2
+                    [obj.fileHandle obj.pathHandle] = getFile('*.cmp', 'Open a CMP Mapfile...');
+                else
+                    [obj.fileHandle obj.pathHandle] = uigetfile('*.cmp', 'Open a CMP Mapfile...');
+                end
+                if ~obj.fileHandle
+                    disp('No file was selected.'); 
+                    return; 
+                end
+                mapfileDataCell = importdata([obj.pathHandle obj.fileHandle], ' ', 200);
+            else
+                mapfileDataCell = importdata(fileName, ' ', 200);
+            end
+            mapfileDataCellParsed = regexp(mapfileDataCell, '\t', 'split');
+            if size(mapfileDataCellParsed, 2) == 1
+                mapfileDataCellParsed = regexp(mapfileDataCell, '\s+', 'split');
+            end
+            lastJunkIDX = 1;
+            while 1
+                if size(mapfileDataCellParsed{lastJunkIDX}, 2) == 6 || size(mapfileDataCellParsed{lastJunkIDX}, 2) == 5
+                    if ~isempty(str2num(mapfileDataCellParsed{lastJunkIDX}{1})) && ...
+                    ~isempty(str2num(mapfileDataCellParsed{lastJunkIDX}{2})) && ...
+                    ~isempty(str2num(mapfileDataCellParsed{lastJunkIDX}{4}))
+                    lastJunkIDX = lastJunkIDX - 1;
+                        break;
+                    end
+                end
+                lastJunkIDX = lastJunkIDX + 1;
+            end            
+            mapfileDataCellParsed(1:lastJunkIDX) = [];
+            for i = 1:size(mapfileDataCellParsed, 1)
+                if ~all(isspace(mapfileDataCellParsed{i}))
+                    obj.Column(i) = str2num(mapfileDataCellParsed{i,:}{1});
+                    obj.Row(i)    = str2num(mapfileDataCellParsed{i,:}{2});
+                    obj.Bank(i)   = mapfileDataCellParsed{i,:}{3}-'@';
+                    obj.Pin(i)    = str2num(mapfileDataCellParsed{i,:}{4});
+                    ElectNum      = str2num(mapfileDataCellParsed{i,:}{5}(5:end));
+                    if isempty(ElectNum)
+                        obj.ElecNum(i) = str2num(mapfileDataCellParsed{i,:}{5}(2:end-4));
+                    else
+                        obj.ElecNum(i) = ElectNum;
+                    end
+                    obj.ChanNum(i)  = (obj.Bank(i) - 1) * 32 + obj.Pin(i);
+                    obj.Label{i}    = mapfileDataCellParsed{i,:}{5};
+                end
+            end
+        end
+    end
+    methods
+        function validFlag = isValid(obj)
+            if ~obj.getFilename
+                validFlag = 0;
+            else
+                validFlag = 1;
+            end
+        end
+        function FilePath = getPathName(obj)
+            FilePath = obj.pathHandle;
+        end
+        function FileName = getFilename(obj)
+            FileName = obj.fileHandle;
+        end
+        function Channel = Electrode2Channel(obj, Electrode)
+            if ~exist('Electrode', 'var'); disp('Electrode is a required input. Refer to help for more information.'); return; end;
+            if isempty(obj.ChanNum(obj.ElecNum == Electrode(1)))
+                disp('Electrode number is invalid.');
+                Channel = [];
+                return;
+            end
+            for ElecIDX = 1:length(Electrode)
+                Channel(ElecIDX) = obj.ChanNum(obj.ElecNum == Electrode(ElecIDX));
+            end
+        end
+        function Electrode = Channel2Electrode(obj, Channel)
+            if isempty(obj.ElecNum(obj.ChanNum == Channel(1)))
+                disp('Channel number is invalid.');
+                Electrode = [];
+                return;
+            end            
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            for ChanIDX = 1:length(Channel)
+                Electrode(ChanIDX) = obj.ElecNum(obj.ChanNum == Channel(ChanIDX));
+            end
+        end
+        function BankID = getChannelBankID(obj, Channel)
+            BankID = obj.Bank(obj.ChanNum == Channel);
+        end
+        function Label = getChannelLabel(obj, Channel)
+            Label = char(obj.Label{obj.ChanNum == Channel});
+        end
+        function Pin = getChannelPin(obj, Channel)
+            Pin = obj.Pin(obj.ChanNum == Channel);
+        end
+        function spHandle = GenerateChannelSubplot(obj, Channel)
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            [x, y] = getChannelColumnRow(obj, Channel);
+            spHandle=subplot('position', [x/10+0.004, y/10+0.004, 1/10-0.004, 1/10-0.004]);
+            axis off;
+            box on;
+            set(spHandle,'XTickLabel', []);
+            set(spHandle,'YTickLabel', []);
+            %%
+        end
+        function GenerateChannelSubplotNames(obj, Channel, fColor)
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            if ~exist('fColor', 'var'); fColor  = [1,1,1]; end
+            Electrode = Channel2Electrode(obj, Channel);
+            text(0.13, 0.23, ['elec ', num2str(Electrode)], 'Color', fColor, 'FontSize', 8);
+            text(0.13, 0.10, ['chan ', num2str(Channel)], 'Color', fColor, 'FontSize', 8);            
+        end
+        function [x, y] = getChannelColumnRow(obj, Channel)
+            if ~exist('Channel', 'var'); disp('Channel is a required input. Refer to help for more information.'); return; end;
+            x = obj.Column(obj.ChanNum == Channel);
+            y = obj.Row(obj.ChanNum == Channel);
+        end
+        function PlotCMP(obj)
+            figure;
+            for Channel = 1:96
+                GenerateChannelSubplot(obj, Channel);
+                GenerateChannelSubplotNames(obj, Channel, [0,0,0]);
+            end
+        end
+        function setAxisBackgroundColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'Color', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                	set(gca, 'Color', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end
+        function setXAxisColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'XColor', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                    set(gca, 'XColor', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end
+        function setYAxisColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'YColor', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                    set(gca, 'YColor', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end
+        function setAxesColor(~, curColor)
+            if isa(curColor, 'double') && (length(curColor) == 3)
+                if all(curColor <= 1) && all(curColor >= 0)
+                    set(gca, 'YColor', curColor);
+                    set(gca, 'XColor', curColor);
+                else
+                    disp('The color values have to be between 0 and 1.');
+                end
+            elseif isa(curColor, 'char')
+                try
+                    set(gca, 'YColor', curColor);
+                    set(gca, 'XColor', curColor);
+                catch
+                    disp('Color is not valid. Type ''doc color'' for more information.');
+                end
+            else                    
+                disp('The input needs to be a valid color input.');
+                disp('A valid color input is a vector of length 3 of values between 0 and 1.');
+            end
+        end        
+    end
+end

BIN
code/matlab_scripts/NPMK/Dependent Functions/.DS_Store


+ 35 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/all-wcprops

@@ -0,0 +1,35 @@
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svnroot/npmk/!svn/ver/51/Dependent%20Functions
+END
+parseCommand.m
+K 25
+svn:wc:ra_dav:version-url
+V 62
+/svnroot/npmk/!svn/ver/53/Dependent%20Functions/parseCommand.m
+END
+getFolder.m
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svnroot/npmk/!svn/ver/53/Dependent%20Functions/getFolder.m
+END
+getSettingFileFullPath.m
+K 25
+svn:wc:ra_dav:version-url
+V 72
+/svnroot/npmk/!svn/ver/53/Dependent%20Functions/getSettingFileFullPath.m
+END
+getFile.m
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/npmk/!svn/ver/53/Dependent%20Functions/getFile.m
+END
+sortNEV.m
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/npmk/!svn/ver/53/Dependent%20Functions/sortNEV.m
+END

+ 222 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/entries

@@ -0,0 +1,222 @@
+10
+
+dir
+51
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/Dependent%20Functions
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2012-03-27T23:44:26.915984Z
+51
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+parseCommand.m
+file
+53
+
+
+
+2011-10-27T11:57:49.000000Z
+2c0fa90cdc7364b84fc07620237d27bf
+2012-03-27T23:52:06.189964Z
+53
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1883
+
+getFolder.m
+file
+53
+
+
+
+2011-10-27T11:57:49.000000Z
+4860508434bed8c9f67a6232860c4ad0
+2012-03-27T23:52:06.189964Z
+53
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1244
+
+getSettingFileFullPath.m
+file
+53
+
+
+
+2011-10-27T11:57:49.000000Z
+77979e01bd62638c4915a653bbc8bd01
+2012-03-27T23:52:06.189964Z
+53
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+350
+
+getFile.m
+file
+53
+
+
+
+2012-01-07T22:05:27.000000Z
+84119ccf4186fe81837a601f4269ba24
+2012-03-27T23:52:06.189964Z
+53
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2334
+
+sortNEV.m
+file
+53
+
+
+
+2012-01-08T04:56:25.000000Z
+37067aeca53f645a593ee37274df3414
+2012-03-27T23:52:06.189964Z
+53
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3878
+
+getFile.ini
+file
+55
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+deleted
+

+ 68 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/getFile.m.svn-base

@@ -0,0 +1,68 @@
+function [dataFilename dataFolder] = getFile(filterSpec, title)
+
+% getFile
+%
+% Similar to uigetfile, it opens a dialogue to get a file, but it also
+% remembers the last folder location, so the user will not need to navigate
+% to the same folder multiple times.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use [dataFilename dataFolder] = getFile(filterSpec)
+%
+%   filterSpec:   The type of file to show. For example, if set to '*.txt'
+%   (OPTIONAL)    only text files will be visible for choosing.
+%                 DEFAULT: *.*, so all files are shown.
+%
+%   title:        This parameter will be the title of the dialogue box.
+%   (OPTIONAL)    DEFAULT: No title will be shown.
+%
+%   dataFilename: The name of the chosen file.
+%
+%   dataFolder:   The path of the chosen file.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   USAGE EXAMPLE: 
+%   
+%   [fileName pathName] = getFile('*.jpg');
+%
+%   In this example a dialogue will open and only show all jpg files. The
+%   name of the chosen file and the path to it are stores in fileName and
+%   pathName respectively.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Salt Lake City, UT
+%   Contributors: 
+%   
+%   Version 1.0.0.0 - October 29, 2010 
+%   Last edit by: Kian Torab
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if ~exist('filterSpec', 'var')
+    filterSpec = '*.*';
+end
+
+if ~exist('title', 'var')
+    title = '';
+end
+
+settingFileFullPath = getSettingFileFullPath('getFile');
+
+%% Opens the getFolder.ini file to see what the last accessed folder was
+if exist(settingFileFullPath, 'file') == 2
+    settingsFID = fopen(settingFileFullPath, 'r');
+    defaultOpenLocation = fscanf(settingsFID, '%200c');
+    fclose(settingsFID);
+    [dataFilename dataFolder] = uigetfile([defaultOpenLocation filterSpec], title);
+else
+    [dataFilename dataFolder] = uigetfile(filterSpec, title);
+end
+
+%% Saves the last opened folder in the getFolder.ini file for later use
+if ischar(dataFolder)
+    settingsFID = fopen(settingFileFullPath, 'w');
+    fprintf(settingsFID, '%s', dataFolder);
+    fclose(settingsFID);
+end

+ 39 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/getFolder.m.svn-base

@@ -0,0 +1,39 @@
+% getFolder
+%
+% Similar to uigetdir except that it will remember the location of the
+% last opened folder.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use plotAverageWaveforms
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Salt Lake City, UT
+%   
+%   Version 1.0.0.0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function dataFolder = getFolder
+
+settingFileFullPath = getSettingFileFullPath('getFolder');
+
+%% Opens the getFolder.ini file to see what the last accessed folder was
+if exist(settingFileFullPath, 'file') == 2
+    settingsFID = fopen(settingFileFullPath, 'r');
+    defaultOpenLocation = fscanf(settingsFID, '%200c');
+    fclose(settingsFID);
+else
+    defaultOpenLocation = [];
+end
+
+%% Gets a folder by opening the last accessed folder as the last location
+dataFolder = uigetdir(defaultOpenLocation);
+
+%% Saves the last opened folder in the getFolder.ini file for later use
+if ischar(dataFolder)
+    settingsFID = fopen(settingFileFullPath, 'w');
+    fprintf(settingsFID, '%s', dataFolder);
+    fclose(settingsFID);
+end

+ 11 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/getSettingFileFullPath.m.svn-base

@@ -0,0 +1,11 @@
+function settingFileFullPath = getSettingFileFullPath(functionName)
+
+settingFileFullPath = which(functionName);
+
+if ~isempty(settingFileFullPath)
+    settingFilePath = fileparts(settingFileFullPath);
+    settingFileFullPath = [settingFilePath '\' functionName '.ini'];
+else
+    disp('Function not valid.');
+    settingFileFullPath = [];
+end

+ 56 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/parseCommand.m.svn-base

@@ -0,0 +1,56 @@
+% parseCommand
+%
+% Parses out a string in the format specified below, into a structure.
+%
+% CommandType:ParamName1=ParamValue1;ParamName2=ParamValue2;
+%
+% The command string can have as many parameters in it as possible.
+%
+% Example:
+%   ExpParameters:TaskType=Disc;StimPattern=0;SRad=10.0000;PRad=30.0000;Int
+%   =0.2000;Xpos=0.0000;Ypos=5.0000;Dur=0.2000;
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kianabc@kianabc.com
+%   Department of Bioengineering
+%   University of Utah
+%   Contributors: 
+%   
+%   Version 1.3.0.0 - November 2, 2010 
+%   Last edit by: Kian Torab
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [parsedCommand errorFlag] = parseCommand(inputString)
+
+errorFlag = 0;
+inputString(find(inputString == '#')) = [];
+colonPos = find(inputString == ':', 1);
+parsedCommand.Type = inputString(1:colonPos-1);
+inputString = inputString(colonPos+1:end);
+try
+    splitString = regexp(inputString(1:end), ';', 'split');
+    splitString(end) = [];
+    if isempty(inputString(find(inputString == '=')))
+        parsedCommand.Value = splitString{:};
+    else        
+        splitParams = regexp(splitString', '=', 'split');
+        splitParams = reshape([splitParams{:}], 2, length(splitString))';
+        if isempty(splitString)
+            parsedCommand = [];
+            errorFlag = 1;
+        else
+            for idx = 1:length(splitString)
+                [numVal, OK] = str2num(splitParams{idx, 2}); %#ok<ST2NM>
+                if OK
+                    parsedCommand.(splitParams{idx,1}) = numVal;
+                else
+                    parsedCommand.(splitParams{idx,1}) = splitParams{idx, 2};
+                end
+            end
+        end
+    end
+catch
+    disp(['Cannot parse: ' inputString]);
+    errorFlag = 1;
+end

+ 115 - 0
code/matlab_scripts/NPMK/Dependent Functions/.svn/text-base/sortNEV.m.svn-base

@@ -0,0 +1,115 @@
+function [SortedStruct, SortedIndeces] = sortNEV(STRUCT, field, TestValue, Report)
+
+% This function extracts information out of a structure based on the field
+% values. The outputs can be the sorted structure and the indeces of those
+% extracted fields. 
+%
+% Use [SortedStruct, SortedIndeces] = sortNEV(STRUCT, field, TestValue, Report)
+%
+%   STRUCT:     The structure to be used for extraction.
+%
+%   field:      The field in STRUCT that is set as criteria for extraction.
+%               This parameter is optional. If not passed, the function
+%               will prompt the user to provide the name of the field.
+%
+%   TestValue:  The value that "field" needs to be equal to in order to
+%               get extracted.
+%               This parameter is optional. If not passed, the function
+%               will prompt the user to provide the value.
+%
+%   Report:     If this flag is set to 1 the function will show a short
+%               summary of the data that was processed.
+%               This parametere is optional.
+%               DEFAULT: will not show report.
+%
+%   OUTPUT
+%
+%   SortedStruct:   The sorted structure output.
+%   
+%   SortedIndeces:  The indeces to the sorted elements.
+%
+%   Example: 
+%   
+%   [NewStruct, Indeces] = sortNEV(MainStruct, 'TestField', 3, 1);
+%
+%   In the example above, the MainStruct is the structure containing all
+%   elements. The function will search through MainStruct and extract all
+%   elements that have their 'TestField' field set to '3'. It will also
+%   show a report of how many elemenets were processed and how many were
+%   extracted.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   
+%   Version 1.4.1.0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Validates all passed on parameters and will prompt user for any missing
+%  parameter.
+
+if ~exist('field', 'var')
+    field = input('What is the name of the field of interest? ');
+end
+
+while ~isfield(STRUCT, field)
+    display('The field name does not exist. Try again.');
+    field = input('What is the name of the field of interest? ');
+end
+
+if ~exist('TestValue', 'var')
+    TestValue = input('What value does the field need to be equal to (string format)? ');
+end
+
+if ~exist('Report', 'var')
+    Report = 0;
+end
+
+%% Searches through the structure to extract the elements of interest.
+SortedIndeces = NaN(1,length(STRUCT));
+if isa(TestValue, 'double')
+%     display(['Please verify to make sure the field ' field ' does not contain any [] data or the sort will not be successful.'])
+    for strIDX = 1:length(STRUCT)
+        if find(STRUCT(strIDX).(field) == TestValue)
+            SortedIndeces(strIDX) = 1;
+        else
+            SortedIndeces(strIDX) = 0;
+        end
+    end
+    SortedStruct = STRUCT(find(SortedIndeces==1));
+else
+    for strIDX = 1:length(STRUCT)
+        if strcmpi(STRUCT(strIDX).(field), TestValue)
+            SortedIndeces(strIDX) = 1;
+        else
+            SortedIndeces(strIDX) = 0;
+        end
+    end
+    SortedStruct = STRUCT(find(SortedIndeces==1));
+end
+
+
+%% Will define as an empty structure of no instances were found.
+if ~exist('SortedStruct', 'var')
+    display('No instances found.');
+    SortedStruct = struct([]);
+else
+
+%% If the flag is set, it will show a report of how many files were
+%  processed.
+if Report == 1
+    if isempty(SortedStruct)
+        display('No instances found.');
+    else
+        display([num2str(length(SortedStruct)) ' many instances were found and extracted.']);
+    end
+end
+
+%% Will force the function to send an output argument to the caller
+%  environment.
+if (nargout == 0)
+    assignin('caller', 'SortedStruct', SortedStruct);
+end
+
+end

BIN
code/matlab_scripts/NPMK/Dependent Functions/bnsx.dat


+ 85 - 0
code/matlab_scripts/NPMK/Dependent Functions/getFile.m

@@ -0,0 +1,85 @@
+function [dataFilename, dataFolder] = getFile(filterSpec, title)
+
+% getFile
+%
+% Similar to uigetfile, it opens a dialogue to get a file, but it also
+% remembers the last folder location, so the user will not need to navigate
+% to the same folder multiple times.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use [dataFilename dataFolder] = getFile(filterSpec)
+%
+%   filterSpec:   The type of file to show. For example, if set to '*.txt'
+%   (OPTIONAL)    only text files will be visible for choosing.
+%                 DEFAULT: *.*, so all files are shown.
+%
+%   title:        This parameter will be the title of the dialogue box.
+%   (OPTIONAL)    DEFAULT: No title will be shown.
+%
+%   dataFilename: The name of the chosen file.
+%
+%   dataFolder:   The path of the chosen file.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   USAGE EXAMPLE: 
+%   
+%   [fileName pathName] = getFile('*.jpg');
+%
+%   In this example a dialogue will open and only show all jpg files. The
+%   name of the chosen file and the path to it are stores in fileName and
+%   pathName respectively.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Salt Lake City, UT
+%   Contributors: 
+%   
+%   Version 1.1.0.0
+%   Last edit by: Kian Torab
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.1.0:
+%   - Initial release.
+%
+% 1.0.1.0:
+%   - Minor update to the help and some formatting. 
+%
+% 1.0.2.0: July 4, 2014
+%   - Allows for selection of NSx files only.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if ~exist('filterSpec', 'var')
+    filterSpec = '*.*';
+end
+
+if ~exist('title', 'var')
+    title = '';
+end
+
+settingFileFullPath = getSettingFileFullPath('getFile');
+
+%% Opens the getFolder.ini file to see what the last accessed folder was
+if exist(settingFileFullPath, 'file') == 2
+    settingsFID = fopen(settingFileFullPath, 'r');
+    defaultOpenLocation = fscanf(settingsFID, '%200c');
+    fclose(settingsFID);
+    backDir = cd;
+    if exist(defaultOpenLocation, 'dir') == 7
+        cd(defaultOpenLocation);
+    end
+    [dataFilename, dataFolder] = uigetfile(filterSpec, title);
+    cd(backDir);
+else
+    [dataFilename, dataFolder] = uigetfile(filterSpec, title);
+end
+
+%% Saves the last opened folder in the getFolder.ini file for later use
+if ischar(dataFolder)
+    settingsFID = fopen(settingFileFullPath, 'w');
+    fprintf(settingsFID, '%s', dataFolder);
+    fclose(settingsFID);
+end

+ 39 - 0
code/matlab_scripts/NPMK/Dependent Functions/getFolder.m

@@ -0,0 +1,39 @@
+% getFolder
+%
+% Similar to uigetdir except that it will remember the location of the
+% last opened folder.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use plotAverageWaveforms
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Salt Lake City, UT
+%   
+%   Version 1.0.0.0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function dataFolder = getFolder
+
+settingFileFullPath = getSettingFileFullPath('getFolder');
+
+%% Opens the getFolder.ini file to see what the last accessed folder was
+if exist(settingFileFullPath, 'file') == 2
+    settingsFID = fopen(settingFileFullPath, 'r');
+    defaultOpenLocation = fscanf(settingsFID, '%200c');
+    fclose(settingsFID);
+else
+    defaultOpenLocation = [];
+end
+
+%% Gets a folder by opening the last accessed folder as the last location
+dataFolder = uigetdir(defaultOpenLocation);
+
+%% Saves the last opened folder in the getFolder.ini file for later use
+if ischar(dataFolder)
+    settingsFID = fopen(settingFileFullPath, 'w');
+    fprintf(settingsFID, '%s', dataFolder);
+    fclose(settingsFID);
+end

+ 15 - 0
code/matlab_scripts/NPMK/Dependent Functions/getSettingFileFullPath.m

@@ -0,0 +1,15 @@
+function settingFileFullPath = getSettingFileFullPath(functionName)
+
+settingFileFullPath = which(functionName);
+
+if ~isempty(settingFileFullPath)
+    settingFilePath = fileparts(settingFileFullPath);
+    if ismac
+        settingFileFullPath = [settingFilePath '/' functionName '.ini'];
+    else
+        settingFileFullPath = [settingFilePath '\' functionName '.ini'];
+    end
+else
+    disp('Function not valid.');
+    settingFileFullPath = [];
+end

+ 148 - 0
code/matlab_scripts/NPMK/Dependent Functions/parseCCF.m

@@ -0,0 +1,148 @@
+function CCF = parseCCF(varargin)
+
+% parseCCF
+%
+% Parses an XML CCF file.
+%
+%   Nick Halper
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.1.0.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 1.1.0.0: January 18, 2016 - Kian Torab
+%   - Minor bug fix with file loading.
+%
+% 1.1.1.0: January 19, 2016 - Kian Torab
+%   - Added a progress bar.
+%
+% 1.1.2.0: October 20, 2016 - Saman Hagh-gooie
+%   - Fixed a invalid character bug.
+%   - Bug fixes with file loading
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+if nargin ~= 0
+    fullfilename = varargin{1};
+else
+    fullfilename = [];
+end
+
+if ~exist(fullfilename, 'file')
+    [fileName pathName] = getFile('*.ccf', 'Choose a CCF file...');
+    fullfilename = [pathName fileName];
+else
+    [pathName, fileName, ext] = fileparts(fullfilename);
+    pathName = [pathName];
+    fileName = [fileName, ext];
+end
+
+prevDecodedXMLCCF = [fullfilename(1:end-3) 'xmld'];
+
+if exist(prevDecodedXMLCCF, 'file') == 2
+    load(prevDecodedXMLCCF, '-mat');
+    return;
+end
+
+disp('The CCF loading can take up to half an hour the first time. Please be patient.');
+
+OBJ = xmlread(fullfile(pathName,fileName));
+removeIndentNodes(OBJ.getChildNodes);
+CCF = parseChildNodes(OBJ);
+
+save(prevDecodedXMLCCF, 'CCF');
+
+%function children = parseChildNodes(OBJ)
+function children = parseChildNodes(theNode)
+% Recurse over node children.
+children = 0;
+if theNode.hasChildNodes
+   childNodes = theNode.getChildNodes;
+   numChildNodes = childNodes.getLength;
+   allocCell = cell(1, numChildNodes);
+
+   children = struct(             ...
+      'Name', allocCell, 'Attributes', allocCell,    ...
+      'Data', allocCell, 'Children', allocCell);    
+
+   counter=0; % added by SH 05.oct.2016
+    for count = 1:numChildNodes
+        theChild = childNodes.item(count-1);
+        children(count) = makeStructFromNode(theChild);
+        counter = counter + 1;
+        if mod(counter,20) == 0
+            fprintf('.');
+        end
+    end
+end
+
+
+%function nodeStruct - makeStructFromNode(OBJ)
+function nodeStruct = makeStructFromNode(theNode)
+nodeStruct = struct(...
+    'Name',char(theNode.getNodeName),...
+    'Attributes', parseAttributes(theNode),...
+    'Data','',...
+    'Children', parseChildNodes(theNode));
+
+
+if any(strcmp(methods(theNode), 'getData'))
+    nodeStruct.Data = char(theNode.getData);
+else
+    nodeStruct.Data = '';
+end
+
+
+
+
+function attributes = parseAttributes(theNode)
+% Create attributes structure.
+
+attributes = [];
+if theNode.hasAttributes
+   theAttributes = theNode.getAttributes;
+   numAttributes = theAttributes.getLength;
+   allocCell = cell(1, numAttributes);
+   attributes = struct('Name', allocCell, 'Value', ...
+                       allocCell);
+
+   for count = 1:numAttributes
+      attrib = theAttributes.item(count-1);
+      attributes(count).Name = char(attrib.getName);
+      attributes(count).Value = char(attrib.getValue);
+   end
+end
+
+
+function removeIndentNodes( childNodes )
+
+numNodes = childNodes.getLength;
+remList = [];
+counter = 0;
+for i = numNodes:-1:1
+    counter = counter + 1;
+    if rem(counter,20) == 0
+        fprintf('.');
+    end
+	theChild = childNodes.item(i-1);
+	if (theChild.hasChildNodes)
+        removeIndentNodes(theChild.getChildNodes);
+    else
+        if ( theChild.getNodeType == theChild.TEXT_NODE && ...
+           ~isempty(char(theChild.getData()))         && ...
+           all(isspace(char(theChild.getData()))))
+         remList(end+1) = i-1; % java indexing
+        end
+    end
+end
+for i = 1:length(remList)
+   childNodes.removeChild(childNodes.item(remList(i)));
+end
+
+
+

+ 56 - 0
code/matlab_scripts/NPMK/Dependent Functions/parseCommand.m

@@ -0,0 +1,56 @@
+% parseCommand
+%
+% Parses out a string in the format specified below, into a structure.
+%
+% CommandType:ParamName1=ParamValue1;ParamName2=ParamValue2;
+%
+% The command string can have as many parameters in it as possible.
+%
+% Example:
+%   ExpParameters:TaskType=Disc;StimPattern=0;SRad=10.0000;PRad=30.0000;Int
+%   =0.2000;Xpos=0.0000;Ypos=5.0000;Dur=0.2000;
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kianabc@kianabc.com
+%   Department of Bioengineering
+%   University of Utah
+%   Contributors: 
+%   
+%   Version 1.3.0.0 - November 2, 2010 
+%   Last edit by: Kian Torab
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function [parsedCommand errorFlag] = parseCommand(inputString)
+
+errorFlag = 0;
+inputString(find(inputString == '#')) = [];
+colonPos = find(inputString == ':', 1);
+parsedCommand.Type = inputString(1:colonPos-1);
+inputString = inputString(colonPos+1:end);
+try
+    splitString = regexp(inputString(1:end), ';', 'split');
+    splitString(end) = [];
+    if isempty(inputString(find(inputString == '=')))
+        parsedCommand.Value = splitString{:};
+    else        
+        splitParams = regexp(splitString', '=', 'split');
+        splitParams = reshape([splitParams{:}], 2, length(splitString))';
+        if isempty(splitString)
+            parsedCommand = [];
+            errorFlag = 1;
+        else
+            for idx = 1:length(splitString)
+                [numVal, OK] = str2num(splitParams{idx, 2}); %#ok<ST2NM>
+                if OK
+                    parsedCommand.(splitParams{idx,1}) = numVal;
+                else
+                    parsedCommand.(splitParams{idx,1}) = splitParams{idx, 2};
+                end
+            end
+        end
+    end
+catch
+    disp(['Cannot parse: ' inputString]);
+    errorFlag = 1;
+end

+ 64 - 0
code/matlab_scripts/NPMK/Dependent Functions/syncPatternDetectNEV.m

@@ -0,0 +1,64 @@
+function codeKeeper = syncPatternDetectNEV(NEVStruct)
+
+% syncPatternDetectNEV
+%
+% Finds the code for the SYNC pattern on the SYNC output of Blackrock
+% Microsystems Neural Signal Processor (NSP) recorded by analog input 
+% channel 16 and thresholded as extracted spikes and saved in the NEV file.
+%
+%   INPUT
+%
+%   NEVStruct:  The NEV structure containing the SYNC pulse.
+%
+%   OUTPUT
+%
+%   codeKeeper: A cell structure containing the unique code and their
+%               respective timestamps.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   USAGE EXAMPLE: 
+%   
+%   codeKeeper = syncPatternDetectNEV(NEVStruct)
+%
+%   In the example above, the NEV structure, containing the continueus 
+%   signal from the SYNC pulse is passed to the function. The output will 
+%   contain the unique codes parsed from the signal file and their 
+%   respective timestamps.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: July 7, 2014
+%   - Initial release.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Setup
+separationVar = 'D';
+
+%% Detect the rising edges
+edgeTS = NEVStruct.Data.Spikes.TimeStamp(NEVStruct.Data.Spikes.Electrode == 144);
+differenceTS = double(diff(edgeTS));
+pulseDifferenceLenght = mode(differenceTS);
+
+convertedChar = [];
+for idx = 1:length(differenceTS)
+    if differenceTS(idx) < pulseDifferenceLenght*1.1;
+        convertedChar = [convertedChar, '1'];
+    elseif differenceTS(idx) < 9*pulseDifferenceLenght;
+        convertedChar = [convertedChar, repmat('0', 1, round((differenceTS(idx) - pulseDifferenceLenght)/pulseDifferenceLenght)), '1'];
+    else
+        convertedChar = [convertedChar, separationVar];
+    end
+end
+
+begTS = edgeTS(find(differenceTS > pulseDifferenceLenght * 12) + 1);
+%% 
+begTS = [edgeTS(1) begTS];
+
+codeKeeper{1} = bin2dec(regexp(convertedChar, separationVar, 'split'))';
+codeKeeper{2} = begTS;

+ 67 - 0
code/matlab_scripts/NPMK/Dependent Functions/syncPatternDetectNSx.m

@@ -0,0 +1,67 @@
+function codeKeeper = syncPatternDetectNSx(data)
+
+% syncPatternDetectNSx
+%
+% Finds the code for the SYNC pattern on the SYNC output of Blackrock
+% Microsystems Neural Signal Processor (NSP) recorded by analog input 
+% channel 16 and outputs the unique code and its related timestamp.
+%
+%   INPUT
+%
+%   data:       The data stream containing the SYNC pulse.
+%
+%   OUTPUT
+%
+%   codeKeeper: A cell structure containing the unique code and their
+%               respective timestamps.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   USAGE EXAMPLE: 
+%   
+%   codeKeeper = syncPatternDetectNSx(data)
+%
+%   In the example above, the data, containing the continueus signal from 
+%   the SYNC pulse is passed to the function. The output will contain the
+%   unique codes parsed from the signal file and their respective
+%   timestamps.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: June 8, 2014
+%   - Initial release.
+%
+% 1.0.1.0: July 7, 2014
+%   - Updated the help file
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Setup
+separationVar = 'D';
+
+%% Detect the rising edges
+edgeTS = edgeDetect(data, 10000);
+differenceTS = diff(edgeTS);
+pulseDifferenceLenght = mode(differenceTS);
+
+convertedChar = [];
+for idx = 1:length(differenceTS)
+    if differenceTS(idx) < pulseDifferenceLenght*1.1;
+        convertedChar = [convertedChar, '1'];
+    elseif differenceTS(idx) < 9*pulseDifferenceLenght;
+        convertedChar = [convertedChar, repmat('0', 1, round((differenceTS(idx) - pulseDifferenceLenght)/pulseDifferenceLenght)), '1'];
+    else
+        convertedChar = [convertedChar, separationVar];
+    end
+end
+
+begTS = edgeTS(find(differenceTS > pulseDifferenceLenght * 12) + 1);
+%% 
+begTS = [edgeTS(1) begTS];
+
+codeKeeper{1} = bin2dec(regexp(convertedChar, separationVar, 'split'))';
+codeKeeper{2} = begTS;

+ 73 - 0
code/matlab_scripts/NPMK/Dependent Functions/syncPatternFinderNSx.m

@@ -0,0 +1,73 @@
+function codeKeeper = syncPatternFinderNSx(filenameNSx)
+
+% syncPatternFinderNSx
+% 
+% Canculated the unique 8-bit code and the associated timestamp of the SYNC
+% pulse of the NSP. 
+%
+% Use codeKeeper = syncPatternFinderNSx(filenameNSx)
+% 
+% All input arguments are optional. Input arguments can be in any order.
+%
+%   filenameNSx:  Name of the file to be opened. If the fname is omitted
+%                 the user will be prompted to select a file. 
+%                 DEFAULT: Will open Open File UI.
+%
+%
+%   OUTPUT:       The structure that contains all the unique 8-bit SYNC
+%                 pulse codes and their corresponding timestamps.
+%
+%   Example 1: 
+%   codeKeeper = syncPatternFinderNSx('myTestNS5.ns5');
+%
+%   In the example above, the file myTestNS5.ns5 will be opened and all the
+%   SYNC pulses and their corresponding timestamps will be output in the
+%   codeKeeper structure. 
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Version History
+%
+% 1.0.0.0:  November 1, 2014
+%   - Initial release.
+%
+% 1.0.1.0:  March 28, 2015
+%   - Fixed a bug where the extension wsan't specified for the file when
+%     the input file was not specified.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Opening the file to get the header information
+if ~exist('filenameNSx', 'var')
+    NSx = openNSx('noread');
+    % Determining the file name read
+    filenameNSx = fullfile(NSx.MetaTags.FilePath, NSx.MetaTags.Filename, NSx.MetaTags.FileExt);
+else
+    NSx = openNSx(filenameNSx, 'noread');
+end
+
+if ~isstruct(NSx)
+    disp('Error reading the NSx file. Most likely the file name did not exist.');
+    return;
+end
+
+%% Calculating the variables for the sync signal
+% Figuring out the channel that recorded the sync pulse. This assums that
+% the sync pulse was recorded on analog input 16 on the Cerebus or analog
+% input 3 on the Direct system.
+numberOfChannels = NSx.MetaTags.ChannelCount;
+
+% Calculating the maximum number of points to read
+maxPacketsToRead = 30 * NSx.MetaTags.SamplingFreq;
+if maxPacketsToRead > NSx.MetaTags.DataPoints
+    maxPacketsToRead = NSx.MetaTags.DataPoints;
+end
+
+%% Reading the sync signal
+NSxSync = openNSx(filenameNSx, ['c:' num2str(numberOfChannels)], ['t:1:' num2str(maxPacketsToRead)], 'read');
+
+codeKeeper = syncPatternDetectNSx(NSxSync.Data(1,:));

+ 5 - 0
code/matlab_scripts/NPMK/LoadingEngines/.svn/all-wcprops

@@ -0,0 +1,5 @@
+K 25
+svn:wc:ra_dav:version-url
+V 40
+/svnroot/npmk/!svn/ver/37/LoadingEngines
+END

+ 31 - 0
code/matlab_scripts/NPMK/LoadingEngines/.svn/entries

@@ -0,0 +1,31 @@
+10
+
+dir
+46
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/LoadingEngines
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2011-06-28T04:44:42.888298Z
+37
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+MClust
+dir
+

BIN
code/matlab_scripts/NPMK/LoadingEngines/MClust/.DS_Store


+ 11 - 0
code/matlab_scripts/NPMK/LoadingEngines/MClust/.svn/all-wcprops

@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svnroot/npmk/!svn/ver/37/LoadingEngines/MClust
+END
+BlackrockNEVLoadingEngine.m
+K 25
+svn:wc:ra_dav:version-url
+V 75
+/svnroot/npmk/!svn/ver/62/LoadingEngines/MClust/BlackrockNEVLoadingEngine.m
+END

+ 62 - 0
code/matlab_scripts/NPMK/LoadingEngines/MClust/.svn/entries

@@ -0,0 +1,62 @@
+10
+
+dir
+46
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/LoadingEngines/MClust
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2011-06-28T04:44:42.888298Z
+37
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+BlackrockNEVLoadingEngine.m
+file
+62
+
+
+
+2012-04-26T14:37:53.000000Z
+5f2b26c0999a1957ab341537ce93717a
+2012-04-26T14:38:23.485809Z
+62
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6331
+

+ 144 - 0
code/matlab_scripts/NPMK/LoadingEngines/MClust/.svn/text-base/BlackrockNEVLoadingEngine.m.svn-base

@@ -0,0 +1,144 @@
+function [timeStamps, waveForms] = BlackrockNEVLoadingEngine(fn, recordToGet, recordUnits)
+
+%% 
+% Blackrock Microsystems NEV loading engine for MClust 3.0.
+%
+% Kian Torab
+% support@blackrockmicro.com
+% Blackrock Microsystems
+% 
+% Version 1.1.1.0
+
+
+if ~exist(fn, 'file')
+    disp('File does not exist.');
+    timeStamps = 0;
+    waveForms = 0;
+    return;
+end
+
+%% Reading the entire data if recordUnits is not defined
+if ~exist('recordUnits', 'var')
+    NEV = loadNEV(fn, 'read');
+    %Saving all timestamps from the file into the timeStamp output variable
+    timeStamps = NEV.Data.Spikes.TimeStamp;
+    timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+    %Saving all saveforms from the file into the waveForm output variable
+    waveForms = initializeWaveform(length(timeStamps));
+    waveForms(:,1,:) = NEV.Data.Spikes.Waveform(1:32,:)';
+else
+%% Reading the file depending on what recordUnits is defining
+    switch recordUnits
+        case 1 %Returning timestamp and waveforms for given timestamps
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Saving all timestamps in the timeStamps output variable
+            timeStamps = NEV.Data.Spikes.TimeStamp;
+            %Converting seconds to NEV timestamps
+            recordToGet = timeStampsSecondsToTimestamps(recordToGet,NEV.MetaTags.SampleRes);
+            %Calculating the index of timestamps to get
+            for idx = 1:length(recordToGet)
+                IDXtoGet(idx) = find(timeStamps == recordToGet(idx),1);
+            end
+            %Saving all timestamps requested by the timestamps
+            timeStamps = timeStamps(IDXtoGet);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps  = length(timeStamps);
+            %Preallocating a 3D waveforms matrix
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Saving all waveforms in the waveForms output variable
+            waveForms(:,1,1:32) = NEV.Data.Spikes.Waveform(1:32,IDXtoGet)';
+        case 2 %Returning timestamp and waveforms for given records
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Saving the timestamps for the requested records
+            timeStamps = NEV.Data.Spikes.TimeStamp(1,recordToGet);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps = length(timeStamps);
+            %Saving the waveforms for the requested records
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Saving the waveforms for the requested records
+            waveForms(:,1,1:32) = NEV.Data.Spikes.Waveform(1:32,recordToGet)';        
+        case 3 %Returning timestamp and waveforms for range of given timestamps
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Converting timestamps in seconds to timestamps in samples
+            recordToGet = timeStampsSecondsToTimestamps(recordToGet,NEV.MetaTags.SampleRes);
+            %Parsing out the timestamp range
+            tInitial = recordToGet(1);
+            tEnd = recordToGet(2);
+            %Saving all timestamps in the timeStamps output variable
+            timeStamps = NEV.Data.Spikes.TimeStamp;
+            %Finding timestamps that fall within the range
+            IDX = find(timeStamps <= tEnd & timeStamps >= tInitial);
+            %Saving all timestamps that fall within the range
+            timeStamps = NEV.Data.Spikes.TimeStamp(1,IDX);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps  = length(timeStamps);
+            %Preallocating a 3D waveforms matrix
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Saving all waveforms in the waveForms output variable
+            waveForms(:,1,1:32) = NEV.Data.Spikes.Waveform(1:32,IDX)';
+        case 4 %Returning timestamp and waveforms for the range of given records
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Creating a range out of the record list
+            recordToGet = [recordToGet(1):recordToGet(end)];
+            %Saving the timestamps for the requested records
+            timeStamps = NEV.Data.Spikes.TimeStamp(1,recordToGet);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps = length(timeStamps);
+            %Saving the waveforms for the requested records
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Saving the waveforms for the requested records
+            waveForms(:,1,1:32) = NEV.Data.Spikes.Waveform(1:32,recordToGet)'; 
+        case 5 %Returning the number of records in the file
+            %Loading the NEV file
+            NEV = loadNEV(fn);
+            % Returning the number of spikes
+            timeStamps = size(NEV.Data.Spikes.TimeStamp, 2);
+            waveForms = [];
+        otherwise
+            disp('Invalid input for recordUnit');
+            disp('Values from 1 to 5 are valid only.');
+    end
+end
+
+timeStamps = timeStamps';
+
+%% Uses openNEV (a part of NPMK package: http://bit.ly/brnpmkkit) to open the NEV file
+function NEV = loadNEV(fn, input)
+
+if ~exist('input', 'var')
+    NEV = openNEV(fn);
+    
+elseif strcmpi(input, 'noread')
+    NEV = openNEV(fn);
+    
+elseif ~strcmpi(input, 'read')
+    disp('Invalid input.');
+    
+else
+    NEV = openNEV(fn, 'read');
+end
+
+%% Initializes the waveform variable depending on the number of spikes in the file
+function waveForms = initializeWaveform(numOfTimestamps)
+
+    waveForms = zeros(numOfTimestamps, 4, 32);
+    
+%% Converts the timestamp samples to timestamp values in seconds
+function timeStampsSec = timeStampsToTimestampSeconds(timeStamps, samplingRate)
+
+    timeStampsSec = double(timeStamps) / double(samplingRate);
+
+%% Converts the timestamp seconds to timestamp values in samples
+function timeStamps = timeStampsSecondsToTimestamps(timeStampsSeconds, samplingRate)
+
+    timeStamps = int32(timeStampsSeconds * double(samplingRate));
+        
+        

+ 193 - 0
code/matlab_scripts/NPMK/LoadingEngines/MClust/BlackrockNEVLoadingEngine.m

@@ -0,0 +1,193 @@
+function [timeStamps, waveForms] = BlackrockNEVLoadingEngine(varargin)
+
+%% 
+% Blackrock Microsystems NEV loading engine for MClust 3.0.
+%
+% Kian Torab
+% support@blackrockmicro.com
+% Blackrock Microsystems
+% 
+% Version 1.3.0.0
+%
+% Version 1.4 by Saman Hagh Gooie - 13 October 2016
+%       - Modifed to work with the latest version of the MClust v4.4
+
+
+if nargin == 1
+    fn = varargin{1};
+elseif nargin == 2
+    if strcmp(varargin{1}, 'get')
+        switch (varargin{2})
+            case 'ChannelValidity'
+                timeStamps = [true true true true]; return;
+            case 'ExpectedExtension'
+                timeStamps = '.nev'; return;
+            case 'UseFileDialog'
+                timeStamps = true; return;
+            case 'filenames'
+                timeStamps = false; return;
+            otherwise
+                error('Unknown get condition.');
+        end
+    else
+        error('2 argins requires "get" as the first argument.');
+    end
+elseif nargin == 3
+    fn = varargin{1};
+    recordToGet = varargin{2};
+    recordUnits = varargin{3};
+end
+
+
+if ~exist(fn, 'file')
+    disp('File does not exist.');
+    timeStamps = false;
+    waveForms = false;
+    return;
+end
+clc
+%% Reading the entire data if recordUnits is not defined
+if ~exist('recordUnits', 'var')
+    NEV = loadNEV(fn, 'read');
+    %Determining what channels are in the data file
+    readElectrodes = unique(NEV.Data.Spikes.Electrode);    
+    
+    %Saving all timestamps from the file into the timeStamp output variable
+    timeStamps = NEV.Data.Spikes.TimeStamp(NEV.Data.Spikes.Electrode==readElectrodes(1));
+    timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+    %Saving all saveforms from the file into the waveForm output variable
+    waveForms = initializeWaveform(length(timeStamps));
+   
+    for idx = 1:length(readElectrodes)
+        waveForms(:,idx,:) = NEV.Data.Spikes.Waveform(1:32,NEV.Data.Spikes.Electrode == readElectrodes(idx))';
+    end
+else
+%% Reading the file depending on what recordUnits is defining
+    switch recordUnits
+        case 1 %Returning timestamp and waveforms for given timestamps
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Saving all timestamps in the timeStamps output variable
+            timeStamps = NEV.Data.Spikes.TimeStamp;
+            %Converting seconds to NEV timestamps
+            recordToGet = timeStampsSecondsToTimestamps(recordToGet,NEV.MetaTags.SampleRes);
+            %Calculating the index of timestamps to get
+            for idx = 1:length(recordToGet)
+                IDXtoGet(idx) = find(timeStamps == recordToGet(idx),1);
+            end
+            %Saving all timestamps requested by the timestamps
+            timeStamps = timeStamps(IDXtoGet);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps  = length(timeStamps);
+            %Preallocating a 3D waveforms matrix
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Saving all waveforms in the waveForms output variable
+            waveForms(:,1,1:32) = NEV.Data.Spikes.Waveform(1:32,IDXtoGet)';
+        case 2 %Returning timestamp and waveforms for given records
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Saving the timestamps for the requested records
+            timeStamps = NEV.Data.Spikes.TimeStamp(1,recordToGet);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps = length(timeStamps);
+            %Saving the waveforms for the requested records
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Determining what channels are in the data file
+            readElectrodes = unique(NEV.Data.Spikes.Electrode);    
+            for idx = 1:length(readElectrodes)
+                temp = NEV.Data.Spikes.Waveform(1:32,NEV.Data.Spikes.Electrode == readElectrodes(idx))';
+                waveForms(:,idx,:) = temp(recordToGet,:);
+            end
+        case 3 %Returning timestamp and waveforms for range of given timestamps
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Converting timestamps in seconds to timestamps in samples
+            recordToGet = timeStampsSecondsToTimestamps(recordToGet,NEV.MetaTags.SampleRes);
+            %Parsing out the timestamp range
+            tInitial = recordToGet(1);
+            tEnd = recordToGet(2);
+            %Saving all timestamps in the timeStamps output variable
+            timeStamps = NEV.Data.Spikes.TimeStamp;
+            %Finding timestamps that fall within the range
+            IDX = find(timeStamps <= tEnd & timeStamps >= tInitial);
+            %Saving all timestamps that fall within the range
+            timeStamps = NEV.Data.Spikes.TimeStamp(1,IDX);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps  = length(timeStamps);
+            %Preallocating a 3D waveforms matrix
+            waveForms = initializeWaveform(numOfTimestamps);
+            %Determining what channels are in the data file
+            readElectrodes = unique(NEV.Data.Spikes.Electrode);    
+            for idx = 1:length(readElectrodes)
+                temp = NEV.Data.Spikes.Waveform(1:32,NEV.Data.Spikes.Electrode == readElectrodes(idx))';
+                waveForms(:,idx,:) = temp(IDX,:);
+            end
+        case 4 %Returning timestamp and waveforms for the range of given records
+            %Loading the NEV file
+            NEV = loadNEV(fn, 'read');
+            %Creating a range out of the record list
+            recordToGet = [recordToGet(1):recordToGet(end)];
+            %Saving the timestamps for the requested records
+            timeStamps = NEV.Data.Spikes.TimeStamp(1,recordToGet);
+            timeStamps = timeStampsToTimestampSeconds(timeStamps,NEV.MetaTags.SampleRes);
+            %Calculating the number of timestamps
+            numOfTimestamps = length(timeStamps);
+            %Saving the waveforms for the requested records
+            waveForms = initializeWaveform(numOfTimestamps);
+            % Loading the waveforms into a MClust waveform variable
+            readElectrodes = unique(NEV.Data.Spikes.Electrode);
+            for idx = 1:length(readElectrodes)
+                waveForms(:,idx,:) = NEV.Data.Spikes.Waveform(1:32,NEV.Data.Spikes.Electrode == readElectrodes(idx))';
+            end
+            %Saving the waveforms for the requested records
+            waveForms = waveForms(recordToGet, :, :);
+            
+        case 5 %Returning the number of records in the file
+            %Loading the NEV file
+            NEV = loadNEV(fn);
+            % Returning the number of spikes
+            timeStamps = size(NEV.Data.Spikes.TimeStamp, 2)/length(unique(NEV.Data.Spikes.Electrode));
+            waveForms = [];
+        otherwise
+            disp('Invalid input for recordUnit');
+            disp('Values from 1 to 5 are valid only.');
+    end
+end
+
+timeStamps = timeStamps';
+
+%% Uses openNEV (a part of NPMK package: http://bit.ly/brnpmkkit) to open the NEV file
+function NEV = loadNEV(fn, input)
+
+if ~exist('input', 'var')
+    NEV = openNEV(fn, 'nomat', 'nosave');
+    
+elseif strcmpi(input, 'noread')
+    NEV = openNEV(fn, 'nomat', 'nosave');
+    
+elseif ~strcmpi(input, 'read')
+    disp('Invalid input.');
+    
+else
+    NEV = openNEV(fn, 'nomat', 'nosave');
+end
+
+%% Initializes the waveform variable depending on the number of spikes in the file
+function waveForms = initializeWaveform(numOfTimestamps)
+
+    waveForms = zeros(numOfTimestamps, 4, 32);
+    
+%% Converts the timestamp samples to timestamp values in seconds
+function timeStampsSec = timeStampsToTimestampSeconds(timeStamps, samplingRate)
+
+    timeStampsSec = double(timeStamps) / double(samplingRate);
+
+%% Converts the timestamp seconds to timestamp values in samples
+function timeStamps = timeStampsSecondsToTimestamps(timeStampsSeconds, samplingRate)
+
+    timeStamps = int32(timeStampsSeconds * double(samplingRate));
+        
+        

BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Linux/nsNEVLibrary.so


BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/msvcp71.dll


BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/msvcr71.dll


BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/nsNEVLibrary.dll


BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/Windows/nsNEVLibrary64.dll


+ 700 - 0
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/ns/ns.c

@@ -0,0 +1,700 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2003-2005 Neuroshare Project
+//
+// This is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// A copy of the GNU Lesser General Public License can be obtained by writing to:
+//  Free Software Foundation, Inc.,
+//  59 Temple Place, Suite 330,
+//  Boston, MA  02111-1307
+//  USA
+//
+// Contact information:
+//  Kirk Korver
+//  CyberKinetics, Inc.,
+//  391 G Chipeta Way
+//  Salt Lake City,  UT  84108
+//  USA
+//  kkorver at cyberkineticsinc.com
+//
+// Website:
+//  sourceforge.net/projects/neuroshare
+//
+// All other copyrights on this material are replaced by this license agreeement.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// $Author: kirkkorver $
+// $Date: 2005/01/24 05:10:47 $
+// $Revision: 1.1 $
+// $Source: /cvsroot/neuroshare/NSLibraries/ns/ns.c,v $
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Specification : Glue to a neuroshare library
+//
+// Authors       : Gopal Santhanam
+//
+//////////////////////////////////////////////////////////////////////////////
+
+
+/*=========================================================================
+| Project : Neuroshare API Glue
+| File    : ns.c
+| Version : v1.01
+|--------------------------------------------------------------------------
+| Portions of this file are copyright (c) 2002-2003 Total Phase, Inc.
+| All rights reserved.
+| www.totalphase.com
+|
+| Redistribution and use in source and binary forms, with or without
+| modification, are permitted provided that the following conditions
+| are met:
+|
+| - Redistributions of source code must retain the above copyright
+|   notice, this list of conditions and the following disclaimer.
+|
+| - 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.
+|
+| - Neither the name of Total Phase, Inc. nor the names of its
+|   contributors may be used to endorse or promote products derived from
+|   this software without specific prior written permission.
+|
+| 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 OWNER 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.
+|--------------------------------------------------------------------------
+|
+| API definitions for the Neuroshare file format standard.
+|
+| Use the following files to access Neuroshare files:
+|   ns.h        --  API header file
+|   ns.c        --  API interface module
+|
+| A Neuroshare library is required in conjuction with this module. 
+| For example:
+|   ns_NEV.so   --  Linux shared object
+|      or
+|   ns_NEV.dll  --  Windows dynamic link library
+|
+========================================================================*/
+
+
+/*=========================================================================
+| INCLUDES
+ ========================================================================*/
+/* This #include can be customized to conform to the user's build paths. */
+#include "ns.h"
+
+
+/*=========================================================================
+| VERSION CHECK
+ ========================================================================*/
+#define NS_CFILE_VERSION   0x0103  /* v1.03 */
+#define NS_REQ_LIB_VERSION 0x0103  /* v1.03 */
+
+/*
+ * Make sure that the ns.h was included and that
+ * the version numbers match.
+ */
+#ifndef NS_HEADER_VERSION
+#  error Unable to include ns.h file. Please check include path.
+
+#elif NS_HEADER_VERSION != NS_CFILE_VERSION
+#  error Version mismatch between ns.c and ns.h files.
+
+#endif
+
+
+/*=========================================================================
+| CONSTANTS
+ ========================================================================*/
+#define MAX_SO_PATH 256
+
+
+/*=========================================================================
+| LINUX SUPPORT
+ ========================================================================*/
+#ifdef linux
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+
+#define DLL_HANDLE  void *
+#define SO_EXT      ".so"
+#define stricmp              strcasecmp
+
+
+/*
+ * These functions allow the Linux behavior to emulate
+ * the Windows behavior as specified below in the Windows
+ * support section.
+ * 
+ * First, search for the shared object in the application
+ * binary path, then in the current working directory.
+ * 
+ * Searching the application binary path requires /proc
+ * filesystem support, which is standard in 2.4.x kernels.
+ * 
+ * If the /proc filesystem is not present, the shared object
+ * will not be loaded from the execution path unless that path
+ * is either the current working directory or explicitly
+ * specified in LD_LIBRARY_PATH.
+ */
+static int _checkPath (const char *path, char *so_name) {
+    char *filename = (char *)malloc(strlen(path) +1 + strlen(so_name) +1);
+    int   fd;
+
+    /* Check if the file is readable */
+    sprintf(filename, "%s/%s", path, so_name);
+    fd = open(filename, O_RDONLY);
+    if (fd >= 0) {
+        strncpy(so_name, filename, MAX_SO_PATH);
+        close(fd);
+    }
+
+    /* Clean up and exit */
+    free(filename);
+    return (fd >= 0);
+}
+
+static void _setSearchPath (char *so_name) {
+    char  path[MAX_SO_PATH+1];
+    int   count;
+    char *p;
+
+    /* Make sure that SO_NAME is not an absolute path. */
+    if (so_name[0] == '/')  return;
+
+    /* Check the execution directory name. */
+    count = readlink("/proc/self/exe", path, MAX_SO_PATH);
+    if (count > 0) {
+        path[count] = 0;
+        if ((p = strrchr(path, '/')) != 0)  *p = '\0';
+        if (path[0] == '\0')  strcpy(path, "/");
+
+        /* If there is a match, return immediately. */
+        if (_checkPath(path, so_name))  return;
+    }
+
+    /* Check the current working directory. */
+    p = getcwd(path, MAX_SO_PATH);
+    if (p != 0)  _checkPath(path, so_name);
+}
+
+#endif
+
+
+/*=========================================================================
+| WINDOWS SUPPORT
+ ========================================================================*/
+#if defined(WIN32) || defined(_WIN32)
+
+#include <stdio.h>
+#include <windows.h>
+#include <string.h>
+
+#define DLL_HANDLE           HINSTANCE
+#define dlopen(name, flags)  LoadLibrary(name)
+#define dlsym(handle, name)  GetProcAddress(handle, name)
+#define dlclose(handle)      FreeLibrary(handle);
+#define dlerror()            "Exiting program"
+#define SO_EXT               ".dll"
+#define snprintf             _snprintf
+#define stricmp              _stricmp
+#ifdef __GNUC__
+    #undef stricmp
+    #define stricmp          strcasecmp
+#endif
+
+/*
+ * Use the default Windows DLL loading rules:
+ *   1.  The directory from which the application binary was loaded.
+ *   2.  The application's current directory.
+ *   3a. [Windows NT/2000/XP only] 32-bit system directory
+ *       (default: c:\winnt\System32)
+ *   3b. 16-bit system directory
+ *       (default: c:\winnt\System or c:\windows\system)
+ *   4.  The windows directory
+ *       (default: c:\winnt or c:\windows)
+ *   5.  The directories listed in the PATH environment variable
+ */
+static void _setSearchPath (char *so_name) 
+{
+    /* Do nothing */
+}
+
+#endif
+
+
+/*=========================================================================
+| LIBRARY FUNCTION TABLE
+ ========================================================================*/
+#if defined(WIN32) || defined(_WIN32)
+#  define ns_api_stdcall __stdcall
+#else
+#  define ns_api_stdcall
+#endif
+
+// Types for all of the function pointers
+typedef ns_RESULT (ns_api_stdcall *ns_GetLibraryInfoType)
+        (ns_LIBRARYINFO *pLibraryInfo, UINT32 dwLibraryInfoSize);
+
+typedef ns_RESULT (ns_api_stdcall *ns_OpenFileType)
+        (const char *pszFilename, UINT32 *hFile);
+    
+typedef ns_RESULT (ns_api_stdcall *ns_GetFileInfoType)
+        (UINT32 hFile, ns_FILEINFO *pFileInfo, UINT32 dwFileInfoSize);
+    
+typedef ns_RESULT (ns_api_stdcall *ns_CloseFileType)
+        (UINT32 hFile);
+    
+typedef ns_RESULT (ns_api_stdcall *ns_GetEntityInfoType)
+        (UINT32 hFile, UINT32 dwEntityID, ns_ENTITYINFO *pEntityInfo, UINT32 dwEntityInfoSize);
+
+    /* Event API */
+typedef ns_RESULT (ns_api_stdcall *ns_GetEventInfoType)
+        (UINT32 hFile, UINT32 dwEntityID, ns_EVENTINFO *pEventInfo, UINT32 dwEventInfoSize);
+    
+typedef ns_RESULT (ns_api_stdcall *ns_GetEventDataType)
+        (UINT32 hFile, UINT32 dwEntityID, UINT32 nIndex, double *pdTimeStamp, void *pData,
+         UINT32 dwDataSize, UINT32 *pdwDataRetSize);
+
+
+
+    /* Analog API */
+typedef ns_RESULT (ns_api_stdcall *ns_GetAnalogInfoType)
+        (UINT32 hFile, UINT32 dwEntityID, ns_ANALOGINFO *pAnalogInfo,UINT32 dwAnalogInfoSize);
+    
+typedef ns_RESULT (ns_api_stdcall *ns_GetAnalogDataType)
+        (UINT32 hFile, UINT32 dwEntityID, UINT32 dwStartIndex, UINT32 dwIndexCount, 
+         UINT32 *pdwContCount, double *pData);
+
+
+    /* Segment API */
+typedef ns_RESULT (ns_api_stdcall *ns_GetSegmentInfoType)
+        (UINT32 hFile, UINT32 dwEntityID, ns_SEGMENTINFO *pSegmentInfo,UINT32 dwSegmentInfoSize);
+
+typedef ns_RESULT (ns_api_stdcall *ns_GetSegmentSourceInfoType)
+        (UINT32 hFile, UINT32 dwEntityID, UINT32 dwSourceID, ns_SEGSOURCEINFO *pSourceInfo,
+         UINT32 dwSourceInfoSize);
+
+typedef ns_RESULT (ns_api_stdcall *ns_GetSegmentDataType)
+        (UINT32 hFile, UINT32 dwEntityID, INT32 nIndex, double *pdTimeStamp, double *pdData,
+         UINT32 dwDataBufferSize, UINT32 *pdwSampleCount, UINT32 *pdwUnitID );
+
+
+    /* Neural API */
+typedef ns_RESULT (ns_api_stdcall *ns_GetNeuralInfoType)
+        (UINT32 hFile, UINT32 dwEntityID, ns_NEURALINFO *pNeuralInfo, UINT32 dwNeuralInfoSize);
+
+typedef ns_RESULT (ns_api_stdcall *ns_GetNeuralDataType)
+        (UINT32 hFile, UINT32 dwEntityID, UINT32 dwStartIndex, UINT32 dwIndexCount, double *pdData);
+
+
+    /* More General API */
+typedef ns_RESULT (ns_api_stdcall *ns_GetIndexByTimeType)
+        (UINT32 hFile, UINT32 dwEntityID, double dTime, INT32 nFlag, UINT32 *pdwIndex);
+
+typedef ns_RESULT (ns_api_stdcall *ns_GetTimeByIndexType)
+        (UINT32 hFile, UINT32 dwEntityID, UINT32 dwIndex, double *pdTime);
+
+typedef ns_RESULT (ns_api_stdcall *ns_GetLastErrorMsgType)
+        (char *pszMsgBuffer, UINT32 dwMsgBufferSize);
+
+
+
+struct NS_LIBRARY_FUNCS 
+{
+    char so_name[MAX_SO_PATH+1];
+    int valid;
+    int refCount;
+    DLL_HANDLE dllHandle;
+    
+    /* General API */
+    ns_GetLibraryInfoType ns_GetLibraryInfo;
+    
+    ns_OpenFileType ns_OpenFile;
+    ns_GetFileInfoType ns_GetFileInfo;
+    ns_CloseFileType ns_CloseFile;
+    
+    ns_GetEntityInfoType ns_GetEntityInfo;
+
+    /* Event API */
+    ns_GetEventInfoType ns_GetEventInfo;
+    ns_GetEventDataType ns_GetEventData;
+
+    /* Analog API */
+    ns_GetAnalogInfoType ns_GetAnalogInfo;
+    ns_GetAnalogDataType ns_GetAnalogData;
+
+    /* Segment API */
+    ns_GetSegmentInfoType ns_GetSegmentInfo;
+    ns_GetSegmentSourceInfoType ns_GetSegmentSourceInfo;
+    ns_GetSegmentDataType ns_GetSegmentData;
+
+    /* Neural API */
+    ns_GetNeuralInfoType ns_GetNeuralInfo;
+    ns_GetNeuralDataType ns_GetNeuralData;
+    
+    /* More General API */
+    ns_GetIndexByTimeType ns_GetIndexByTime;
+    ns_GetTimeByIndexType ns_GetTimeByIndex;
+    ns_GetLastErrorMsgType ns_GetLastErrorMsg;
+};
+
+
+#define MAX_LIBS 32
+
+/* This is initialized to zero as per ANSI C specifications */
+static struct NS_LIBRARY_FUNCS _libraries[MAX_LIBS];
+
+#define CHECK_VALIDITY(nsDllHandle)                  \
+    if (nsDllHandle < 1 || nsDllHandle > MAX_LIBS || \
+        _libraries[nsDllHandle-1].valid == 0)        \
+        return ns_LIBERROR;
+
+
+/*=========================================================================
+| SHARED LIBRARY LOADER
+ ========================================================================*/
+/* The error conditions can be customized depending on the application. */
+/* a return value of 0 indicates an error */
+ns_DLLHANDLE ns_stdcall ns_LoadLibrary (const char *libname)
+{
+    int i;
+    DLL_HANDLE handle;
+
+    ns_LIBRARYINFO lib_info;
+    UINT32 lib_api_version;
+
+    char so_name[MAX_SO_PATH+1];
+    
+    for (i=0; i < MAX_LIBS; ++i) 
+    {
+        if (_libraries[i].valid && !strcmp(libname, _libraries[i].so_name)) 
+        {
+            ++_libraries[i].refCount;
+            return (i+1);
+        }
+    }
+
+    /* Find an open slot */
+    for (i=0; i < MAX_LIBS; ++i) 
+    {
+        if (!_libraries[i].valid)
+            break;
+    }
+
+    /* Return an error if we don't have enough slots left */
+    if (i == MAX_LIBS)
+        return ns_LIBERROR;
+
+    /* Add the extension if necessary */
+    {
+        const char * pExt;      /* point to the extension */
+        pExt = libname + strlen(libname) - strlen(SO_EXT);
+        if (pExt < libname) /* allow for really short library names) */
+            pExt = libname;
+
+        /* strcmp ignoring case */
+        if (stricmp(pExt, SO_EXT) == 0)
+            snprintf(so_name, MAX_SO_PATH, "%s", libname);              /* copy the name */
+        else
+            snprintf(so_name, MAX_SO_PATH, "%s%s", libname, SO_EXT);    /* copy the name, add extension */
+
+        so_name[MAX_SO_PATH] = 0;   /* force termination */
+    }
+    
+    _setSearchPath(so_name);
+    handle = dlopen(so_name, RTLD_LAZY);
+    if (handle == 0) 
+    {
+#if 1
+        fprintf(stderr, "ns.c: Unable to load %s\n", so_name);
+        fprintf(stderr, "ns.c: %s\n", dlerror());
+#endif
+        return 0;
+    }
+    
+    _libraries[i].ns_GetLibraryInfo = (ns_GetLibraryInfoType)dlsym(handle,
+                                                    "ns_GetLibraryInfo");
+    
+    if (_libraries[i].ns_GetLibraryInfo == 0) 
+    {
+#if 1
+        fprintf(stderr, "ns.c: Unable to bind %s ns_GetLibraryInfo function\n",
+                so_name);
+        fprintf(stderr, "ns.c: %s\n", dlerror());
+#endif
+        dlclose(handle);
+        return 0;
+    }
+
+    /* test for compatible versions */
+    _libraries[i].ns_GetLibraryInfo(&lib_info, sizeof(lib_info));
+    
+    lib_api_version = ((lib_info.dwAPIVersionMaj << 8) & 0xff00) |
+                      ((lib_info.dwAPIVersionMin << 0) & 0x00ff);
+    
+#if 0       /* ALL VERSIONS ARE COMPATIBLE */
+    if (lib_api_version  < NS_REQ_LIB_VERSION ||
+        NS_CFILE_VERSION < lib_api_version)
+    {
+#if 1
+        fprintf(stderr, "\nns.c:Incompatible versions:\n");
+        
+        fprintf(stderr, "ns.c:  NS Glue version     = v%d.%02d  ",
+                (NS_CFILE_VERSION >> 8) & 0xff, NS_CFILE_VERSION & 0xff);
+        
+        if (lib_api_version < NS_REQ_LIB_VERSION)
+            fprintf(stderr, "(requires Library API version >= %d.%02d)\n",
+                    (NS_REQ_LIB_VERSION >> 8) & 0xff,
+                    (NS_REQ_LIB_VERSION >> 0) & 0xff);
+        else
+            fprintf(stderr, "(Library API version OK)\n");
+        
+        fprintf(stderr, "ns.c:  Library API version = v%d.%02d  ",
+                (lib_api_version >> 8) & 0xff, lib_api_version  & 0xff);
+
+        if (NS_CFILE_VERSION < NS_REQ_LIB_VERSION)
+            fprintf(stderr, "(requires NS Glue version >= %d.%02d)\n",
+                    (lib_api_version  >> 8) & 0xff,
+                    (lib_api_version  >> 0) & 0xff);
+        else
+            fprintf(stderr, "(NS Glue version OK)\n");
+        
+#endif
+        dlclose(handle);
+        return 0;
+    }
+#endif
+
+
+// This macro only works because several conventions are followed
+// 1) A function named foo, has a type (typedef) called fooType
+// 2) The name of the function in our structure is the same name as 3)
+// 3) The exported DLL name is the same name as 2)
+#define LOAD_LIBRARY(func)                                           \
+    {                                                                \
+        _libraries[i].func = (func##Type)dlsym(handle, #func);       \
+        if (_libraries[i].func == 0) {                               \
+            fprintf(stderr, "ns.c: Unable to bind %s %s function\n", \
+                    so_name, #func);                                 \
+            fprintf(stderr, "ns.c: %s\n", dlerror());                \
+            goto error;                                              \
+        }                                                            \
+    }
+
+
+    /* More General API */
+    LOAD_LIBRARY(ns_OpenFile);
+    LOAD_LIBRARY(ns_GetFileInfo);
+    LOAD_LIBRARY(ns_CloseFile);
+    LOAD_LIBRARY(ns_GetEntityInfo);
+
+    /* Event API */
+    LOAD_LIBRARY(ns_GetEventInfo);
+    LOAD_LIBRARY(ns_GetEventData);
+
+    /* Analog API */
+    LOAD_LIBRARY(ns_GetAnalogInfo);
+    LOAD_LIBRARY(ns_GetAnalogData);
+
+    /* Segment API */
+    LOAD_LIBRARY(ns_GetSegmentInfo);
+    LOAD_LIBRARY(ns_GetSegmentSourceInfo);
+    LOAD_LIBRARY(ns_GetSegmentData);
+
+    /* Neural API */
+    LOAD_LIBRARY(ns_GetNeuralInfo);
+    LOAD_LIBRARY(ns_GetNeuralData);
+
+    /* More General API */
+    LOAD_LIBRARY(ns_GetIndexByTime);
+    LOAD_LIBRARY(ns_GetTimeByIndex);
+    LOAD_LIBRARY(ns_GetLastErrorMsg);
+
+#undef LOAD_LIBRARY
+
+    /* Setup the other variables in the library structure */
+    _libraries[i].valid     = 1;
+    _libraries[i].dllHandle = handle;
+    _libraries[i].refCount  = 1;
+    strncpy(_libraries[i].so_name, so_name, MAX_SO_PATH);
+    _libraries[i].so_name[MAX_SO_PATH] = 0;
+    
+    return (i+1);
+
+error:
+    dlclose(handle);
+    return 0;
+}
+
+ns_RESULT ns_stdcall ns_CloseLibrary (ns_DLLHANDLE nsDllHandle)
+{
+    CHECK_VALIDITY(nsDllHandle)
+        
+    --_libraries[nsDllHandle -1].refCount;
+    if (_libraries[nsDllHandle -1].refCount == 0) {
+        dlclose(_libraries[nsDllHandle -1].dllHandle);
+        _libraries[nsDllHandle -1].valid = 0;
+    }
+    
+    return ns_OK;
+}
+
+            
+/*=========================================================================
+| GENERAL API
+ ========================================================================*/
+ns_RESULT ns_stdcall ns_GetLibraryInfo (ns_DLLHANDLE nsDllHandle, ns_LIBRARYINFO *pLibraryInfo, UINT32 dwLibraryInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetLibraryInfo(pLibraryInfo, dwLibraryInfoSize);
+}
+    
+ns_RESULT ns_stdcall ns_OpenFile (ns_DLLHANDLE nsDllHandle, const char *pszFilename, UINT32 *hFile)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_OpenFile(pszFilename, hFile);
+}
+    
+ns_RESULT ns_stdcall ns_GetFileInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, ns_FILEINFO *pFileInfo, UINT32 dwFileInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetFileInfo(hFile, pFileInfo, dwFileInfoSize);
+}
+    
+ns_RESULT ns_stdcall ns_CloseFile (ns_DLLHANDLE nsDllHandle, UINT32 hFile)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_CloseFile(hFile);
+}
+    
+ns_RESULT ns_stdcall ns_GetEntityInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, ns_ENTITYINFO *pEntityInfo, UINT32 dwEntityInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetEntityInfo(hFile, dwEntityID, pEntityInfo, dwEntityInfoSize);
+}
+
+
+/*=========================================================================
+| EVENT API
+ ========================================================================*/
+ns_RESULT ns_stdcall ns_GetEventInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, ns_EVENTINFO *pEventInfo, UINT32 dwEventInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetEventInfo(hFile, dwEntityID, pEventInfo, dwEventInfoSize);
+}
+    
+ns_RESULT ns_stdcall ns_GetEventData (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, UINT32 nIndex, double *pdTimeStamp, void *pData,
+                           UINT32 dwDataSize, UINT32 *pdwDataRetSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetEventData(hFile, dwEntityID, nIndex, pdTimeStamp, pData, dwDataSize, pdwDataRetSize);
+}
+
+
+/*=========================================================================
+| ANALOG API
+ ========================================================================*/
+ns_RESULT ns_stdcall ns_GetAnalogInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, ns_ANALOGINFO *pAnalogInfo, UINT32 dwAnalogInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetAnalogInfo(hFile, dwEntityID, pAnalogInfo, dwAnalogInfoSize);
+}
+    
+ns_RESULT ns_stdcall ns_GetAnalogData (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, UINT32 dwStartIndex, UINT32 dwIndexCount, 
+                            UINT32 *pdwContCount, double *pData)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetAnalogData(hFile, dwEntityID, dwStartIndex, dwIndexCount, pdwContCount, pData);
+}
+
+
+/*=========================================================================
+| SEGMENT API
+ ========================================================================*/
+ns_RESULT ns_stdcall ns_GetSegmentInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, ns_SEGMENTINFO *pSegmentInfo, UINT32 dwSegmentInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetSegmentInfo(hFile, dwEntityID, pSegmentInfo, dwSegmentInfoSize);
+}
+
+ns_RESULT ns_stdcall ns_GetSegmentSourceInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, UINT32 dwSourceID, ns_SEGSOURCEINFO *pSourceInfo,
+                                   UINT32 dwSourceInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetSegmentSourceInfo(hFile, dwEntityID, dwSourceID, pSourceInfo, dwSourceInfoSize);
+}
+
+ns_RESULT ns_stdcall ns_GetSegmentData (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, UINT32 nIndex, double *pdTimeStamp, double *pdData,
+                             UINT32 dwDataBufferSize, UINT32 *pdwSampleCount, UINT32 *pdwUnitID )
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetSegmentData(hFile, dwEntityID, nIndex, pdTimeStamp, pdData,
+                                      dwDataBufferSize, pdwSampleCount, pdwUnitID );
+}
+
+
+/*=========================================================================
+| NEURAL API
+ ========================================================================*/
+ns_RESULT ns_stdcall ns_GetNeuralInfo (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, ns_NEURALINFO *pNeuralInfo, UINT32 dwNeuralInfoSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetNeuralInfo(hFile, dwEntityID, pNeuralInfo, dwNeuralInfoSize);
+}
+
+ns_RESULT ns_stdcall ns_GetNeuralData (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, UINT32 dwStartIndex, UINT32 dwIndexCount, double *pdData)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetNeuralData(hFile, dwEntityID, dwStartIndex, dwIndexCount, pdData);
+}
+
+    
+/*=========================================================================
+| MORE GENERAL API
+ ========================================================================*/
+ns_RESULT ns_stdcall ns_GetIndexByTime (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, double dTime, INT32 nFlag, UINT32 *pdwIndex)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetIndexByTime(hFile, dwEntityID, dTime, nFlag, pdwIndex);
+}
+
+ns_RESULT ns_stdcall ns_GetTimeByIndex (ns_DLLHANDLE nsDllHandle, UINT32 hFile, UINT32 dwEntityID, UINT32 dwIndex, double *pdTime)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetTimeByIndex(hFile, dwEntityID, dwIndex, pdTime);
+}
+
+ns_RESULT ns_stdcall ns_GetLastErrorMsg (ns_DLLHANDLE nsDllHandle, char *pszMsgBuffer, UINT32 dwMsgBufferSize)
+{
+    CHECK_VALIDITY(nsDllHandle)
+    return _libraries[nsDllHandle-1].ns_GetLastErrorMsg(pszMsgBuffer, dwMsgBufferSize);
+}

+ 776 - 0
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/NevLIb-3-05/ns/ns.h

@@ -0,0 +1,776 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2003-2004 Neuroshare Project
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// A copy of the GNU Lesser General Public License can be obtained by writing to:
+//  Free Software Foundation, Inc.,
+//  59 Temple Place, Suite 330,
+//  Boston, MA  02111-1307
+//  USA
+//
+// Contact information:
+//  Kirk Korver
+//  CyberKinetics, Inc.,
+//  391 G Chipeta Way
+//  Salt Lake City,  UT  84108
+//  USA
+//  kkorver at cyberkineticsinc.com
+//
+// Website:
+//  sourceforge.net/projects/neuroshare
+//
+// All other copyrights on this material are replaced by this license agreeement.
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// $Author: putermutt $
+// $Date: 2007/01/24 00:50:10 $
+// $Revision: 1.2 $
+// $Source: /cvsroot/neuroshare/NSLibraries/ns/ns.h,v $
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Specification : API definitions for the Neuroshare file format standard.
+//
+// Description   : Neuroshare API Glue
+// Use the following files to access Neuroshare files:
+//   ns.h        --  API header file
+//   ns.c        --  API interface module
+//
+// A Neuroshare library is required in conjuction with this module. 
+// For example:
+//   ns_NEV.so   --  Linux shared object
+//      or
+//   ns_NEV.dll  --  Windows dynamic link library
+//
+// Authors       : Gopal Santhanam
+//
+// $Date: 2007/01/24 00:50:10 $
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef NS_H_INCLUDED   // Include guards
+#define NS_H_INCLUDED
+
+
+/*=========================================================================
+| VERSION
+ ========================================================================*/
+#define NS_HEADER_VERSION  0x0103  /* v1.03 */
+
+
+/*=========================================================================
+| C++ SUPPORT
+ ========================================================================*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*=========================================================================
+| TYPES
+ ========================================================================*/
+#if defined(__GNUC__)
+    typedef char           INT8;
+    typedef unsigned char  UINT8;
+    typedef short          INT16;
+    typedef unsigned short UINT16;
+    typedef int            INT32;
+    typedef unsigned int   UINT32;
+    typedef unsigned long long  UINT64;
+
+    // Specify 4 byte structure alignment
+    #define GCC_ALIGN_4     __attribute__((aligned(4)))
+    
+    
+#elif defined(_MSC_VER)
+    #include <windows.h>
+    
+    // Copied from the Feb2003 SDK, just in case it isn't installed
+    typedef signed char         INT8, *PINT8;
+    typedef signed short        INT16, *PINT16;
+    typedef signed int          INT32, *PINT32;
+    typedef signed __int64      INT64, *PINT64;
+    typedef unsigned char       UINT8, *PUINT8;
+    typedef unsigned short      UINT16, *PUINT16;
+    typedef unsigned int        UINT32, *PUINT32;
+    typedef unsigned __int64    UINT64, *PUINT64;
+
+
+    // specify 4-byte structure alignment
+    #pragma pack(push, 4)       
+    #define GCC_ALIGN_4
+
+#endif
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Library Return Code Definitions
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef    INT32 ns_RESULT;
+
+typedef enum {
+    ns_OK        =  0,  //Function Successful
+    ns_LIBERROR  = -1,  //Linked Library Error
+    ns_TYPEERROR = -2,  //Library unable to open file type
+    ns_FILEERROR = -3,  //File access or read Error
+    ns_BADFILE   = -4,  //Invalid file handle passed to function
+    ns_BADENTITY = -5,  //Invalid or inappropriate entity identifier specified
+    ns_BADSOURCE = -6,  //Invalid source identifier specified
+    ns_BADINDEX  = -7   //Invalid entity index or index range specified
+} ns_STATUS;
+    
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 
+// Definitions of constants and flags 
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Library description flags
+typedef enum {
+    ns_LIBRARY_DEBUG         = 0x01,  // includes debug info linkage
+    ns_LIBRARY_MODIFIED      = 0x02,  // file was patched or modified
+    ns_LIBRARY_PRERELEASE    = 0x04,  // pre-release or beta version
+    ns_LIBRARY_SPECIALBUILD  = 0x08,  // different from release version
+    ns_LIBRARY_MULTITHREADED = 0x10,  // library is multithread safe
+} ns_LIBRARY_FLAGS;
+
+//Definitions of Event Entity types
+typedef enum {
+    ns_EVENT_TEXT  = 0,  // null-terminated ascii text string
+    ns_EVENT_CSV   = 1,  // comma separated ascii text values
+    ns_EVENT_BYTE  = 2,  // 8-bit value
+    ns_EVENT_WORD  = 3,  // 16-bit value
+    ns_EVENT_DWORD = 4,  // 32-bit value
+} ns_EVENT_TYPE;
+
+//Definitions of entity types in the structure ns_ENTITYINFO
+typedef enum {
+    ns_ENTITY_UNKNOWN     = 0,     // unknown entity type
+    ns_ENTITY_EVENT       = 1,     // Event entity
+    ns_ENTITY_ANALOG      = 2,     // Analog entity
+    ns_ENTITY_SEGMENT     = 3,     // Segment entity
+    ns_ENTITY_NEURALEVENT = 4,     // Sorted Neural entity
+} ns_ENTITY_TYPE;
+
+//Flags used for locating data entries
+typedef enum {
+    ns_BEFORE  = -1,  // less than or equal to specified time    
+    ns_CLOSEST =  0,  // closest time 
+    ns_AFTER   = +1,  // greater than or equal to specified time
+} ns_LOCATION_FLAGS;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 
+//             DLL library version information functions
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+//File descriptor structure
+typedef struct
+{
+    char szDescription[32];    // Text description of the file type or file family
+    char szExtension[8];       // Extension used on PC, Linux, and Unix Platforms
+    char szMacCodes[8];        // Application and Type Codes used on Mac Platforms
+    char szMagicCode[16];      // Null-terminated code used at the file beginning
+} GCC_ALIGN_4  ns_FILEDESC;
+
+// Library information structure
+typedef struct 
+{
+    UINT32 dwLibVersionMaj;    // Major version number of library
+    UINT32 dwLibVersionMin;    // Minor version number of library
+    UINT32 dwAPIVersionMaj;    // Major version number of API
+    UINT32 dwAPIVersionMin;    // Minor version number of API
+    char   szDescription[64];  // Text description of the library
+    char   szCreator[64];      // Name of library creator
+    UINT32 dwTime_Year;        // Year of last modification date
+    UINT32 dwTime_Month;       // Month (1-12; January = 1) of last modification date
+    UINT32 dwTime_Day;         // Day of the month (1-31) of last modification date
+    UINT32 dwFlags;            // Additional library flags
+    UINT32 dwMaxFiles;         // Maximum number of files library can simultaneously open
+    UINT32 dwFileDescCount;    // Number of valid description entries in the following array
+    ns_FILEDESC FileDesc[16];  // Text descriptor of files that the DLL can interpret
+} GCC_ALIGN_4  ns_LIBRARYINFO;
+
+// File information structure (the time of file creation should be reported in GMT)
+typedef struct
+{
+    char   szFileType[32];         // Manufacturer's file type descriptor
+    UINT32 dwEntityCount;          // Number of entities in the data file.
+    double dTimeStampResolution;   // Minimum timestamp resolution
+    double dTimeSpan;              // Time span covered by the data file in seconds
+    char   szAppName[64];          // Name of the application that created the file
+    UINT32 dwTime_Year;            // Year the file was created
+    UINT32 dwTime_Month;           // Month (1-12; January = 1)
+    UINT32 dwTime_DayofWeek;       // Day of the week (0-6; Sunday = 0)
+    UINT32 dwTime_Day;             // Day of the month (1-31)
+    UINT32 dwTime_Hour;            // Hour since midnight (0-23)
+    UINT32 dwTime_Min;             // Minute after the hour (0-59)
+    UINT32 dwTime_Sec;             // Seconds after the minute (0-59)
+    UINT32 dwTime_MilliSec;        // Milliseconds after the second (0-1000)
+    char   szFileComment[256];     // Comments embedded in the source file
+} GCC_ALIGN_4  ns_FILEINFO;
+
+// General entity information structure
+typedef struct
+{
+    char   szEntityLabel[32];  // Specifies the label or name of the entity
+    UINT32 dwEntityType;       // One of the ns_ENTITY_* types defined above
+    UINT32 dwItemCount;        // Number of data items for the specified entity in the file
+} ns_ENTITYINFO;
+    
+// Event entity information structure
+typedef struct
+{
+    UINT32 dwEventType;      // One of the ns_EVENT_* types defined above
+    UINT32 dwMinDataLength;  // Minimum number of bytes that can be returned for an Event
+    UINT32 dwMaxDataLength;  // Maximum number of bytes that can be returned for an Event
+    char   szCSVDesc[128];   // Description of the data fields for CSV Event Entities
+} GCC_ALIGN_4  ns_EVENTINFO;
+
+// Analog information structure
+typedef struct
+{
+    double    dSampleRate;           // The sampling rate in Hz used to digitize the analog values
+    double    dMinVal;               // Minimum possible value of the input signal
+    double    dMaxVal;               // Maximum possible value of the input signal
+    char    szUnits[16];             // Specifies the recording units of measurement
+    double    dResolution;           // Minimum resolvable step (.0000305 for a +/-1V 16-bit ADC)  
+    double    dLocationX;            // X coordinate in meters
+    double    dLocationY;            // Y coordinate in meters
+    double    dLocationZ;            // Z coordinate in meters
+    double    dLocationUser;         // Additional position information (e.g. tetrode number)
+    double    dHighFreqCorner;       // High frequency cutoff in Hz of the source signal filtering
+    UINT32    dwHighFreqOrder;       // Order of the filter used for high frequency cutoff
+    char    szHighFilterType[16];    // Type of filter used for high frequency cutoff (text format)
+    double    dLowFreqCorner;        // Low frequency cutoff in Hz of the source signal filtering
+    UINT32    dwLowFreqOrder;        // Order of the filter used for low frequency cutoff
+    char    szLowFilterType[16];     // Type of filter used for low frequency cutoff (text format)
+    char    szProbeInfo[128];        // Additional text information about the signal source
+} GCC_ALIGN_4  ns_ANALOGINFO;
+    
+//Segment Information structure
+typedef struct
+{
+    UINT32 dwSourceCount;     // Number of sources in the Segment Entity, e.g. 4 for a tetrode
+    UINT32 dwMinSampleCount;  // Minimum number of samples in each Segment data item
+    UINT32 dwMaxSampleCount;  // Maximum number of samples in each Segment data item
+    double dSampleRate;       // The sampling rate in Hz used to digitize source signals
+    char   szUnits[32];       // Specifies the recording units of measurement
+} GCC_ALIGN_4  ns_SEGMENTINFO;
+
+// Segment source information structure
+typedef struct
+{
+    double dMinVal;               // Minimum possible value of the input signal
+    double dMaxVal;               // Maximum possible value of the input signal
+    double dResolution;           // Minimum input step size that can be resolved
+    double dSubSampleShift;       // Time diff btn timestamp and actual sampling time of source
+    double dLocationX;            // X coordinate of source in meters
+    double dLocationY;            // Y coordinate of source in meters
+    double dLocationZ;            // Z coordinate of source in meters
+    double dLocationUser;         // Additional position information (e.g tetrode number)
+    double dHighFreqCorner;       // High frequency cutoff in Hz of the source signal filtering
+    UINT32 dwHighFreqOrder;       // Order of the filter used for high frequency cutoff
+    char   szHighFilterType[16];  // Type of filter used for high frequency cutoff (text format)
+    double dLowFreqCorner;        // Low frequency cutoff in Hz of the source signal filtering
+    UINT32 dwLowFreqOrder;        // Order of the filter used for low frequency cutoff
+    char   szLowFilterType[16];   // Type of filter used for low frequency cutoff (text format)
+    char   szProbeInfo[128];      // Additional text information about the signal source
+} GCC_ALIGN_4  ns_SEGSOURCEINFO;
+
+// Neural Information structure
+typedef struct
+{
+    UINT32 dwSourceEntityID;  // Optional ID number of a source entity
+    UINT32 dwSourceUnitID;    // Optional sorted unit ID number used in the source entity
+    char   szProbeInfo[128];  // Additional probe text information or source entity label
+} GCC_ALIGN_4  ns_NEURALINFO;
+
+typedef INT32 ns_DLLHANDLE;
+
+    
+#if !defined(NS_COMPILING_LIB)
+#  define NS_FIRST_ARG ns_DLLHANDLE nssDllHANDLE,
+#  define ns_stdcall
+#else
+#  define NS_FIRST_ARG
+#  if defined(WIN32) || defined(_WIN32)
+#    define ns_stdcall __stdcall
+#  else
+#    define ns_stdcall
+#  endif
+#endif
+    
+    
+
+/*=========================================================================
+| PROTOTYPES
+ ========================================================================*/
+ns_DLLHANDLE ns_stdcall ns_LoadLibrary  (const char *libname);
+ns_RESULT    ns_stdcall ns_CloseLibrary (ns_DLLHANDLE nsDllHandle);
+    
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetLibraryInfo
+//  
+// Purpose:
+//  Retrieves information about the loaded API library
+//
+// Parameters:
+//  ns_LIBRARYINFO *pLibraryInfo       pointer to ns_LIBRARYINFO structure to receive information
+//  UINT32 dwLibraryInfoSize           size in bytes of ns_LIBRARYINFO structure
+//
+// Return Values:
+//  ns_OK                              ns_LIBIRARYINFO successfully retrieved
+//  ns_LIBEERROR                       library error
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetLibraryInfo
+        (NS_FIRST_ARG ns_LIBRARYINFO *pLibraryInfo, UINT32 dwLibraryInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_OpenFile
+//  
+// Purpose:
+//    Opens the data file and assigns a file handle for internal use by the library.
+//
+// Parameters:
+//  char *pszFilename                  name of file to open
+//  UINT32 *hFile                      pointer to a file handle
+//
+// Return Values:
+//  ns_OK                              ns_LIBIRARYINFO successfully retrieved
+//  ns_TYPEERROR                       library unable to open file type
+//  ns_FILEERROR                       file access or read error 
+//  ns_LIBEERROR                       library error
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_OpenFile
+    (NS_FIRST_ARG const char *pszFilename, UINT32 *hFile);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetFileInfo
+//  
+// Purpose:
+//  Retrieve general information about the data file
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  ns_FILEINFO *pFileInfo             pointer to ns_FILEINFO structure that receives data
+//  UINT32 dwFileInfoSize              number of bytes returned in ns_FILEINFO
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_FILEERROR                       file access or read error
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetFileInfo
+    (NS_FIRST_ARG UINT32 hFile, ns_FILEINFO *pFileInfo, UINT32 dwFileInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_CloseFile
+//  
+// Purpose:
+//  Close the open data file
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_CloseFile
+    (NS_FIRST_ARG UINT32 hFile);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetEntityInfo
+//  
+// Purpose:
+//  Retrieve Entity information
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  entity ID
+//  ns_ENTITYINFO *pEntityInfo         pointer to ns_ENTITYINFO structure that receives information 
+//  UINT32 dwEntityInfoSize            number of bytes returned in ns_ENTITYINFO
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetEntityInfo
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, ns_ENTITYINFO *pEntityInfo, UINT32 dwEntityInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetEventInfo
+//  
+// Purpose:
+//  Retrieve information for Event entities.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Event entity ID
+//  ns_EVENTINFO *pEventInfo           pointer to ns_EVENTINFO structure to receive information 
+//  UINT32 dwEventInfoSize             number of bytes returned in ns_EVENTINFO
+//
+// Return Values:
+//  ns_OK                function succeeded
+//  ns_BADFILE            invalid file handle
+//  ns_BADENTITY            inappropriate or invalid entity identifier
+//  ns_LIBERROR            library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetEventInfo
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, ns_EVENTINFO *pEventInfo, UINT32 dwEventInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetEventData
+//  
+// Purpose:
+//  Retrieve the timestamp and Event entity data items.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Event entity ID
+//  UINT32 nIndex                      Event entity item number
+//  double *pdTimeStamp                pointer to double timestamp (in seconds)
+//  void   *pData                      pointer to data buffer to receive data
+//  UINT32 *pdwDataSize                pointer to number of bytes of data retrieved into data buffer
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       inappropriate or invalie entity identifier
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetEventData
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, UINT32 nIndex, double *pdTimeStamp, void *pData,
+     UINT32 dwDataSize, UINT32 *pdwDataRetSize);
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetAnalogInfo
+//
+// Purpose:
+//  Retrieve information for Analog entities
+//
+// Parameters:
+//
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Analog entity ID
+//  ns_ANALOGINFO *pAnalogInfo         pointer to ns_ANALOGINFO structure to receive data 
+//  UINT32 dwAnalogInfoSize            number of bytes returned in ns_ANALOGINFO
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       inappropriate or invalie entity identifier
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetAnalogInfo
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, ns_ANALOGINFO *pAnalogInfo, UINT32 dwAnalogInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetAnalogData
+//  
+// Purpose:
+//  Retrieve analog data in the buffer at pData.  If possible, dwIndexCount, analog data values are
+//  returned in the buffer.  As there may be time gaps in the sequential values, the number of
+//  continuously sampled data items is returned in pdwContCount.
+//
+// Parameters:
+//  UINT32 hFile                      handle to NS data file
+//  UINT32 dwEntityID                 Analog entity ID
+//  UINT32 dwStartIndex               starting index to search for timestamp
+//  UINT32 dwIndexCount               number of timestamps to retrieve
+//  UINT32 *pdwContCount              pointer to count of the first non-sequential analog item
+//  double *pData                     pointer of data buffer to receive data values
+//
+// Return Values:
+//  ns_OK                             function succeeded
+//  ns_BADFILE                        invalid file handle
+//  ns_BADENTITY                      inappropriate or invalid entity identifier
+//  ns_LIBERROR                       library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetAnalogData
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, UINT32 dwStartIndex, UINT32 dwIndexCount, 
+     UINT32 *pdwContCount, double *pData);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetSegmentInfo
+//  
+// Purpose:
+//  Retrieve information for Segment entities.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Segment entity ID
+//  ns_SEGMENTINFO *pSegmentInfo       pointer to ns_SEGMENTINFO structure to receive information
+//  UINT32 dwSegmentInfoSize           size in bytes retrieved in ns_SEGMENTINFO structure
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       invalid or inappropriate entity identifier specified
+//  ns_FILEERROR                       file access or read error
+//  ns_LIBERROR                        library error
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetSegmentInfo
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, ns_SEGMENTINFO *pSegmentInfo, UINT32 dwSegmentInfoSize);
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetSegmentSourceInfo
+//  
+// Purpose:
+//  Retrieve information on the source, dwSourceID, generating segment entity dwEntityID.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Segment entity ID
+//  UINT32 dwSourceID                  entity ID of source
+//  ns_SEGSOURCEINFO *pSourceInfo      pointer to ns_SEGSOURCEINFO structure to receive information
+//  UINT32 dwSourceInfoSize            size in bytes retrieved in ns_SEGSOURCEINFO structure
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       invalid or inappropriate entity identifier specified
+//  ns_FILEERROR                       file access or read error
+//  ns_LIBERROR                        library error
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetSegmentSourceInfo
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, UINT32 dwSourceID, ns_SEGSOURCEINFO *pSourceInfo,
+     UINT32 dwSourceInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetSegmentData
+//  
+// Purpose:
+//  Retrieve segment data waveform and its timestamp.
+//  The number of data points read is returned at pdwSampleCount.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Segment entity ID
+//  INT32 nIndex                       Segment item index to retrieve
+//  double *pdTimeStamp                pointer to timestamp to retrieve
+//  double *pData                      pointer to data buffer to receive data
+//  UINT32 *pdwSampleCount             pointer to number of data items retrieved 
+//  UINT32 *pdwUnitID                  pointer to unit ID of Segment data
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       invalid or inappropriate entity identifier specified
+//  ns_FILEERROR                       file access or read error
+//  ns_LIBERROR                        library error
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetSegmentData
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, UINT32 nIndex, double *pdTimeStamp, double *pdData,
+     UINT32 dwDataBufferSize, UINT32 *pdwSampleCount, UINT32 *pdwUnitID );
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetNeuralInfo
+//  
+// Purpose:
+//  Retrieve information on Neural Events.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Neural entity ID
+//  ns_NEURALINFO *pNeuralInfo         pointer to ns_NEURALINFO structure to receive information 
+//  UINT32 dwNeuralInfoSize            number of bytes returned in ns_NEURALINFO
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       inappropriate or invalid entity identifier
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+ns_RESULT ns_stdcall ns_GetNeuralInfo
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, ns_NEURALINFO *pNeuralInfo, UINT32 dwNeuralInfoSize);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetNeuralData
+//  
+// Purpose:
+//  Retrieve requested number of Neural event timestamps (in sec)
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  Neural event entity ID
+//  UINT32 dwStartIndex                index of first Neural event item time to retrieve
+//  UINT32 dwIndexCount                number of Neural event items to retrieve
+//  double *pData                      pointer to buffer to receive times
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_BADENTITY                       inappropriate or invalie entity identifier
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetNeuralData
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, UINT32 dwStartIndex, UINT32 dwIndexCount, double *pdData);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetIndexByTime
+//  
+// Purpose:
+//  Given the time (sec), return the closest data item index, as specified by nFlag.
+//  Finds the packet with the closest time to the requested time.  
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  entity ID to search for
+//  UINT32 dwSearchTimeStamp           timestamp of item to search for
+//  INT32 nFlag                        position of item relative to the requested timestamp
+//  UINT32 *pdwIndex                   pointer to index of item to retrieve 
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetIndexByTime
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, double dTime, INT32 nFlag, UINT32 *pdwIndex);
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetTimeByIndex
+//  
+// Purpose:
+//  Given an index for an entity data item, return the time in seconds.
+//
+// Parameters:
+//  UINT32 hFile                       handle to NS data file
+//  UINT32 dwEntityID                  entity ID to search for
+//  UINT32 dwIndex                     index of entity item to search for
+//  double *pdTime                     time of entity to retrieve
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_BADFILE                         invalid file handle
+//  ns_LIBERROR                        library error, null pointer
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetTimeByIndex
+    (NS_FIRST_ARG UINT32 hFile, UINT32 dwEntityID, UINT32 dwIndex, double *pdTime);
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ns_GetLastErrorMsg
+//  
+// Purpose:  
+//  Retrieve the most recent error text message
+//
+// Parameters:
+//  char *pszMsgBuffer                 pointer to text buffer to receive error message  
+//  UINT32 dwMsgBufferSize             size in bytes of text buffer
+//
+// Return Values:
+//  ns_OK                              function succeeded
+//  ns_LIBERROR                        library error
+//
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ns_RESULT ns_stdcall ns_GetLastErrorMsg
+    (NS_FIRST_ARG char *pszMsgBuffer, UINT32 dwMsgBufferSize);
+
+
+
+/*=========================================================================
+| PACKING
+ ========================================================================*/
+#if defined(__GNUC__)
+    #undef GCC_ALIGN_4
+#elif defined(_MSC_VER)
+    #pragma pack(pop)
+#endif
+
+
+
+/*=========================================================================
+| C++ SUPPORT
+ ========================================================================*/
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif  // include guards

BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/Nex Setup.jpg


BIN
code/matlab_scripts/NPMK/LoadingEngines/nsNEVLIbrary 3.05/OFS Setup.jpg


BIN
code/matlab_scripts/NPMK/NEV Utilities/.DS_Store


+ 91 - 0
code/matlab_scripts/NPMK/NEV Utilities/findEventTimes.m

@@ -0,0 +1,91 @@
+function [allTimestamps allSnippets allIndices] = findEventTimes(NEV, Channel, Units)
+
+% Given a NEV file, an channel number, and a unit number this function
+% will return indices corresponding to those spikes, timestamps
+% corresponding to those spikes (optional), and snippets corresponding to
+% those spikes (optional). 
+%
+% Use [timestamps snippets indices] = findEventTimes(NEV, Channel, Unit)
+% 
+% INPUTS
+%
+%   NEV:          This corresponds to the NEV file the desired data is
+%                 being extracted from.
+%
+%   Channel:      The channel number the data is being extracted for.
+%
+%   Units:        The unit numbers the data is being extracted for. This
+%                 variable can be one unit or many units passed as an array
+%                 of integers.
+%                 DEFAULY: If units is not specified all timestamps from
+%                 all units will be passed to the calling function. For
+%                 noise pass 255.
+%
+% OUTPUT
+%
+%   indices:      An array of all indices that correspond to neural data
+%                 for channel and unit passed.
+%
+%   timestamps:   An array of all timestamps that correspond to neural data
+%                 for channel and unit passed.
+%
+%   snippets:     A matrix of all indices that correspond to neural data
+%                 for channel and unit passed.
+%
+%   IF OUTPUT IS NOT SPECIFIED only "timestamps" WILL BE PASSED TO THE
+%   CALLING FUNCTION.
+%
+%   Example: 
+%   
+%   [timestamps snippets indices] = findEventTimes(NEV, 3, [1,3:5]);
+%
+%   In the example above, the indices, timestamps, and snippets for
+%   channel #3 and units 1, 3, 4, and 5 will be passed to the calling
+%   function.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Salt Lake City, UT
+%   Version 2.0.0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+if ~exist('Units', 'var')
+    Units = 0:5;
+end
+
+if ischar(Channel) && exist('Units', 'var')
+    strcmpi(Channel, 'DigitalIn')
+        allSnippets = find(NEV.Data.SerialDigitalIO.UnparsedData == Units);
+        allTimestamps = NEV.Data.SerialDigitalIO.TimeStamp(allSnippets);
+        allIndices = [];
+else
+
+    % Find indices that correspond to "Channel"
+    ChannelIndices = find([NEV.Data.Spikes.Electrode] == Channel);
+
+    for i = 1:length(Units)
+        % Find indices that correspond to "Units" within "Channel" indices
+        UnitIndices{i} = find([NEV.Data.Spikes.Unit(ChannelIndices)] == Units(i));
+
+        % Updating the indices so they correspond to the original NEV indices
+        indices{i} = ChannelIndices(UnitIndices{i});
+
+        % Finding the timestamps corresponding to the indices
+        timestamps{i} = NEV.Data.Spikes.TimeStamp(indices{i});
+        % Finding the snippets corresponding to the indices
+        if isfield(NEV.Data.Spikes, 'Waveform')
+            snippets{i} = NEV.Data.Spikes.Waveform(:,indices{i});
+        elseif nargout == 3 && i == 1
+            display('Snippet data was not retrieved because the NEV does not contain any snippets.');
+            snippets{i} = [];
+        end
+    end
+
+    allIndices = cell2mat(indices);
+    allTimestamps = double(cell2mat(timestamps));
+    if exist('snippets', 'var')
+        allSnippets = cell2mat(snippets);
+    end
+end

+ 76 - 0
code/matlab_scripts/NPMK/NEV Utilities/mergeNEV.m

@@ -0,0 +1,76 @@
+function [NEV] = mergeNEV()
+
+%% 
+% Saves a new NEV file that contains event data from one NEV and spike data
+% from another
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Use: mergeNEV()
+
+%mergeNEV version = '1.0.0.0';
+
+%Author: Nick Halper
+%Contact: nhalper@blackrockmicro.com
+
+%% 
+% Choose file that contains event data
+
+
+uiwait(msgbox('Choose the file containing event data (comments, digital inputs, etc) that you want to keep','Choose Event Data','modal'));
+EventNEV = openNEV();
+
+uiwait(msgbox('Choose the file containing sorted spike data that you want to keep','Choose Spike Data','modal'));
+SpikeNEV = openNEV();
+
+
+
+
+for i = 1:length(SpikeNEV.MetaTags.ChannelID)
+    EventIndices = find(EventNEV.Data.Spikes.Electrode == SpikeNEV.MetaTags.ChannelID(i));
+    SpikeDataIndices = find(SpikeNEV.Data.Spikes.Electrode == SpikeNEV.MetaTags.ChannelID(i));
+    
+    EventNEV.Data.Spikes.TimeStamp(EventIndices) = [];
+    EventNEV.Data.Spikes.Electrode(EventIndices) = [];
+    EventNEV.Data.Spikes.Unit(EventIndices) = [];
+    EventNEV.Data.Spikes.Waveform(:,EventIndices) = [];
+    
+    
+    
+    disp('Length of Spike Indices:');
+    disp(length(SpikeDataIndices));
+    
+    disp('Length of Event Indices:');
+    disp(length(EventIndices));
+    
+    EventNEV.Data.Spikes.TimeStamp = [EventNEV.Data.Spikes.TimeStamp SpikeNEV.Data.Spikes.TimeStamp(SpikeDataIndices)];
+    EventNEV.Data.Spikes.Electrode = [EventNEV.Data.Spikes.Electrode SpikeNEV.Data.Spikes.Electrode(SpikeDataIndices)];
+    EventNEV.Data.Spikes.Unit = [EventNEV.Data.Spikes.Unit SpikeNEV.Data.Spikes.Unit(SpikeDataIndices)];
+    EventNEV.Data.Spikes.Waveform = [EventNEV.Data.Spikes.Waveform SpikeNEV.Data.Spikes.Waveform(:,SpikeDataIndices)];
+    
+    [EventNEV.Data.Spikes.TimeStamp, ISort] = sort(EventNEV.Data.Spikes.TimeStamp);
+    EventNEV.Data.Spikes.Electrode = EventNEV.Data.Spikes.Electrode(ISort);
+    EventNEV.Data.Spikes.Unit = EventNEV.Data.Spikes.Unit(ISort);
+    EventNEV.Data.Spikes.Waveform = EventNEV.Data.Spikes.Waveform(:,ISort);
+    
+end
+
+
+SpikeNEV.MetaTags.ChannelID = EventNEV.MetaTags.ChannelID;
+SpikeNEV.MetaTags.HeaderOffset = EventNEV.MetaTags.HeaderOffset;
+EventNEV.MetaTags = SpikeNEV.MetaTags;
+
+
+%EventNEV.Data.Spikes = SpikeNEV.Data.Spikes;
+
+NEV = EventNEV;
+
+
+uiwait(msgbox('Choose the save location for the new file','Choose Save Location','modal'));
+[FileName,PathName] = uiputfile('.nev');
+
+
+SavePath = fullfile(PathName,FileName);
+
+saveNEV(NEV,fullfile(PathName,FileName));
+
+end
+

+ 819 - 0
code/matlab_scripts/NPMK/NEV Utilities/openNEVTracking.m

@@ -0,0 +1,819 @@
+function varargout = openNEV(varargin)
+
+% openNEV
+%
+% Opens an .nev file for reading, returns all file information in a NEV
+% structure. Works with File Spec 2.1 & 2.2 & 2.3.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use OUTPUT = openNEV(fname, 'noread', 'report', 'noparse', 'nowarning', 
+%                             'nosave', 'nomat', 'uV', 'overwrite').
+% 
+% NOTE: All input arguments are optional. Input arguments may be in any order.
+%
+%   fname:        Name of the file to be opened. If the fname is omitted
+%                 the user will be prompted to select a file using an open 
+%                 file user interface. 
+%                 DEFAULT: Will open Open File UI.
+%
+%   'noread':     Will not read the spike waveforms if user passes this argument.
+%                 DEFAULT: will read spike waveform.
+%
+%   'report':     Will show a summary report if user passes this argument.
+%                 DEFAULT: will not show report.
+%
+%   'parse':    The code will not parse the experimental parameters in digital I/O.
+%                 See below for guidelines on how to format your parameters.
+%                 DEFAULT: will not parse the parameters.
+%
+%   'nowarning':  The code will not give a warning if there is an error in
+%                 parsing.
+%                 DEFAULT: will give warning message.
+%
+%   'nosave':     The code will not save a copy of the NEV structure as a
+%                 MAT file. By default the code will save a copy in the same
+%                 folder as the NEV file for easy future access.
+%                 DEFAULT: will save the MAT file.
+%
+%   'nomat':      Will not look for a MAT file. This option will force
+%                 openNEV to open a NEV file instead of any available MAT
+%                 files.
+%                 DEFAULT: will load the MAT file if available.
+%
+%   'uV':         Will read the spike waveforms in unit of uV instead of
+%                 raw values. Note that this conversion may lead to loss of
+%                 information (e.g. 15/4 = 4) since the waveforms type will
+%                 stay in int16. It's recommended to read raw spike
+%                 waveforms and then perform the conversion at a later
+%                 time.
+%                 DEFAULT: will read waveform information in raw.
+%
+%   '8bits':      Indicates that 8 bits on the digital IO port was used
+%                 instead of 16 bits.
+%                 DEFAULT: will assumes that 16 bits of digital IO were used.
+%
+%   't:':         Indicats the time window of the NEV file to be read. For
+%                 example, if t: is set to 2 (i.e. 't:0.6')
+%                 then only the first 2 seconds of the file is to be read. If set
+%                 to 2-50 (i.e. 't:2:50) then the time between 2 seconds
+%                 and 50 seconds will be read.
+%                 DEFAULT: the entire file will be read if 't:xx:xx' is not
+%                 passed to the function.
+%
+%   'overwrite':  If MATLAB loads a NEV file using 'nomat' and a MAT file
+%                 already exists, by default it will prompt the user to
+%                 allow for overwriting the old MAT. Passing the
+%                 'overwrite' flag will automatically overwrite the newly
+%                 opened NEV file ont the old MAT file.
+%                 DEFAULT: will ask the user whether to overwrite the old
+%                 MAT.
+%
+%   OUTPUT:       Contains the NEV structure.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   USAGE EXAMPLE: 
+%   
+%   openNEV('report','read');
+%
+%   In the example above, the file dialogue will prompt for a file. A
+%   report of the file contents will be shown. The digital data will not be
+%   parsed. The data needs to be in the proper format (refer below). The 
+%   spike waveforms are in raw units and not in uV.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   DIGITAL PARAMETERS/MARKERS FORMAT:
+%
+%   In order for this function to parse your experimental parameters they 
+%   need to be in the following format:
+%
+%   *ParamLabel:Parameter1=value1;Parameter2=value2;Parameter3=value3;#
+%
+%   TWO EXAMPLES:
+%   *ExpParameter:Intensity=1.02;Duration=400;Trials=1;PageSegment=14;#
+%
+%   *Stimulation:StimCount=5;Duration=10;#
+%
+%   In the first example, the parameter is of type "ExpParameter". The 
+%   parameters are, "Intensity, Duration, Trials, and PageSement." The 
+%   values of those parameters are, "1.02, 400, 1, and 14," respectively.
+%   The second example is of type "Stimulation". The name of the parameters
+%   are "StimCount" and "Duration" and the values are "5" and "10" 
+%   respectively.
+%   -----------------------------------------------------------------------
+%   It can also read single value markers that follow the following format.
+%
+%   *MarkerName=Value;#
+%
+%   EXAMPLES:  *WaitSeconds=10;# OR  *JuiceStatus=ON;#
+%
+%   The above line is a "Marker". The marker value is 10 in the first 
+%   and it's ON in the second example.
+%   -----------------------------------------------------------------------
+%   Moreover, the marker could be a single value:
+%
+%   *MarkerValue#
+%
+%   EXAMPLES: *JuiceOff#  OR  *HandsOnSwitches#
+%   -----------------------------------------------------------------------
+%   The label, parameter name, and values are flexible and can be anything.
+%   The only required formatting is that the user needs to have a label
+%   followed by a colon ':', followed by a field name 'MarkerVal', followed
+%   by an equal sign '=', followed by the parameter value '10', and end
+%   with a semi-colon ';'.
+%
+%   NOTE:
+%   Every line requires a pound-sign '#' at the very end. 
+%   Every line requires a star sign '*' at the very beginning. If you
+%   use LabVIEW SendtoCerebus.vi by Kian Torab then there is no need for 
+%   a '*' in the beginning.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 4.4.0.0:
+%   - Major performance boost in reading NEV files when tracking data is 
+%   stored in the file.
+%
+% 4.4.0.2:
+%   - Updated documentation.
+%
+% 4.4.0.3: 5 January 2014
+%   - Fixed the way DayOfWeek is read in MetaTags.
+%   - Fixed 'noread' argument, so when passed, openNEV will not read the
+%   spike waveforms.
+%
+% 4.4.1.0: 25 January 2014
+%   - Fixed a bug that resulted from passing 'read' to openNEV.
+%
+% 4.4.2.0: 28 February 2014
+%   - Fixed bug related to loading data with t:XX:XX argument.
+%
+% 4.4.3.0: 12 June 2014
+%   - Fixed a typo in the help.
+%
+% 4.4.3.1: 13 June 2014
+%   - Updated the version numbers in the help and in the function itself.
+%
+% 4.4.3.2: 21 June 2014
+%   - Fixed a bug where Application name wasn't being read properly.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Defining structures
+NEV = struct('MetaTags',[], 'ElectrodesInfo', [], 'Data', []);
+NEV.MetaTags = struct('Subject', [], 'Experimenter', [], 'DateTime', [],...
+    'SampleRes',[],'Comment',[],'FileTypeID',[],'Flags',[], 'openNEVver', [], ...
+    'DateTimeRaw', [], 'FileSpec', [], 'PacketBytes', [], 'HeaderOffset', [], ...
+    'DataDuration', [], 'DataDurationSec', [], 'PacketCount', [], ...
+    'TimeRes', [], 'Application', [], 'Filename', [], 'FilePath', []);
+NEV.Data = struct('SerialDigitalIO', [], 'Spikes', [], 'Comments', [], 'VideoSync', [], ...
+    'Tracking', [], 'TrackingEvents', [], 'PatientTrigger', [], 'Reconfig', []);
+NEV.Data.Spikes = struct('TimeStamp', [],'Electrode', [],...
+    'Unit', [],'Waveform', [], 'WaveformUnit', []);
+NEV.Data.SerialDigitalIO = struct('InputType', [], 'TimeStamp', [],...
+    'TimeStampSec', [], 'Type', [], 'Value', [], 'InsertionReason', [], 'UnparsedData', []);
+NEV.Data.VideoSync = struct('TimeStamp', [], 'FileNumber', [], 'FrameNumber', [], 'ElapsedTime', [], 'SourceID', []);
+NEV.Data.Comments = struct('TimeStamp', [], 'TimeStampSec', [], 'CharSet', [], 'Color', [], 'Text', []);
+NEV.Data.Tracking = [];
+NEV.Data.TrackingEvents = struct('TimeStamp', [], 'TimeStampSec', [], 'Text', []);
+NEV.Data.PatientTrigger = struct('TimeStamp', [], 'TriggerType', []);
+NEV.Data.Reconfig = struct('TimeStamp', [], 'ChangeType', [], 'CompName', [], 'ConfigChanged', []);
+Flags = struct;
+
+NEV.MetaTags.openNEVver = '4.4.3.1';
+
+%% Check for multiple versions of openNEV in path
+if size(which('openNEV', '-ALL'),1) > 1
+    disp('WARNING: There are multiple openNEV functions in the path. Use which openNEV -ALL for more information.');
+end
+
+%% Validating input arguments
+for i=1:length(varargin)
+    switch lower(varargin{i})
+        case 'report'
+            Flags.Report = varargin{i};
+        case 'noread'
+            Flags.ReadData = varargin{i};
+        case 'read'
+            Flags.ReadData = varargin{i};
+        case 'nosave'
+            Flags.SaveFile = varargin{i};
+        case 'nomat'
+            Flags.NoMAT = varargin{i};
+        case 'nowarning'
+            Flags.WarningStat = varargin{i};
+        case 'parse'
+            Flags.ParseData = 'parse';
+        case 'uv'
+            Flags.waveformUnits = 'uV';
+        case '8bits'
+            Flags.digIOBits = '8bits';
+        case 'overwrite'
+            Flags.Overwrite = 'overwrite';
+        otherwise
+            temp = varargin{i};
+            if length(temp)>3 && ...
+                    (strcmpi(temp(3),'\') || ...
+                     strcmpi(temp(1),'/') || ...
+                     strcmpi(temp(2),'/'))                
+                fileFullPath = varargin{i};
+                if exist(fileFullPath, 'file') ~= 2
+                    disp('The file does not exist.');
+                    varargout{1} = [];
+                    return;
+                end
+            elseif length(temp)>3 && strcmpi(temp(1:2),'t:') && ~strcmpi(temp(3), '\') && ~strcmpi(temp(3), '/')
+                temp(1:2) = [];
+                temp = str2num(temp);
+                if length(temp) == 1
+                    fprintf('Only one timepoint (%0.0f) was passed to the function.\n', temp);
+                    fprintf('The initial timepoint is set to 0, so data between 0 and %0.0f will be read.\n', temp);
+                    temp(2) = temp;
+                    temp(1) = 0;
+                end
+                readTime = [temp(1), temp(end)];
+                Flags.SaveFile = 'nosave';
+                Flags.NoMAT = 'nomat';
+            else
+                if ~isnumeric(varargin{i})
+                    disp(['Invalid argument ''' varargin{i} ''' .']);
+                else
+                    disp(['Invalid argument ''' num2str(varargin{i}) ''' .']);
+                end
+                clear variables;
+                if nargout
+                    varargout{1} = [];
+                end
+                return;
+            end
+            clear temp;
+    end
+end; clear i;
+
+%% Defining and validating variables
+if ~exist('fileFullPath', 'var')
+    if exist('getFile.m', 'file') == 2
+        [fileName pathName] = getFile('*.nev', 'Choose a NEV file...');
+    else
+        [fileName pathName] = uigetfile;
+    end
+    fileFullPath = [pathName fileName];
+    if fileFullPath==0; 
+        clear variables; 
+        if nargout
+            varargout{1} = [];
+        end
+        disp('No file was selected.');
+        return
+    end
+end
+
+if ~isfield(Flags, 'Report');        Flags.Report = 'noreport'; end
+if ~isfield(Flags, 'WarningStat');   Flags.WarningStat = 'warning'; end;
+if ~isfield(Flags, 'ReadData');      Flags.ReadData = 'read'; end
+if ~isfield(Flags, 'ParseData');     Flags.ParseData = 'noparse'; end
+if ~isfield(Flags, 'SaveFile');      Flags.SaveFile = 'save'; end;
+if ~isfield(Flags, 'NoMAT');         Flags.NoMAT = 'yesmat'; end;
+if ~isfield(Flags, 'waveformUnits'); Flags.waveformUnits = 'raw'; end;
+if ~isfield(Flags, 'digIOBits');     Flags.digIOBits = '16bits'; end;
+if ~isfield(Flags, 'Overwrite');     Flags.Overwrite = 'noOverwrite'; end;
+if strcmpi(Flags.Report, 'report')
+    disp(['openNEV ' NEV.MetaTags.openNEVver]);
+end
+%%  Validating existance of parseCommand
+if strcmpi(Flags.ParseData, 'parse') 
+    if exist('parseCommand.m', 'file') ~= 2
+        disp('This version of openNEV requires function parseCommand.m to be placed in path.');
+        clear variables;
+        if nargout
+            varargout{1} = [];
+        end
+        return;
+    end
+end
+
+tic;
+matPath = [fileFullPath(1:end-4) '.mat'];
+
+%% Check for a MAT file and load that instead of NEV
+if exist(matPath, 'file') == 2 && strcmpi(Flags.NoMAT, 'yesmat')
+    disp('MAT file corresponding to selected NEV file already exists. Loading MAT instead...');
+    load(matPath);
+    if isempty(NEV.Data.Spikes.Waveform) && strcmpi(Flags.ReadData, 'read')
+        disp('The MAT file does not contain waveforms. Loading NEV instead...');
+    else
+        if ~nargout
+            assignin('base', 'NEV', NEV);
+            clear variables;
+        else
+            varargout{1} = NEV;
+        end
+        return;
+    end
+end
+
+%% Reading BasicHeader information from file
+FID                       = fopen(fileFullPath, 'r', 'ieee-le');
+BasicHeader               = fread(FID, 336, '*uint8');
+NEV.MetaTags.FileTypeID   = char(BasicHeader(1:8)');
+NEV.MetaTags.FileSpec     = [num2str(double(BasicHeader(9))) '.' num2str(double(BasicHeader(10)))];
+NEV.MetaTags.Flags        = dec2bin(double(typecast(BasicHeader(11:12), 'uint16')),16);
+Trackers.fExtendedHeader  = double(typecast(BasicHeader(13:16), 'uint32'));
+NEV.MetaTags.HeaderOffset = Trackers.fExtendedHeader;
+Trackers.countPacketBytes = double(typecast(BasicHeader(17:20), 'uint32'));
+NEV.MetaTags.PacketBytes  = Trackers.countPacketBytes;
+NEV.MetaTags.TimeRes      = double(typecast(BasicHeader(21:24), 'uint32'));
+NEV.MetaTags.SampleRes    = typecast(BasicHeader(25:28), 'uint32');
+t                         = double(typecast(BasicHeader(29:44), 'uint16'));
+tempApp                   = BasicHeader(45:76)';
+tempApp(find(tempApp == 0):end) = [];
+NEV.MetaTags.Application  = char(tempApp); clear tempApp;
+NEV.MetaTags.Comment      = char(BasicHeader(77:332)');
+[NEV.MetaTags.FilePath, NEV.MetaTags.Filename] = fileparts(fileFullPath);
+Trackers.countExtHeader   = typecast(BasicHeader(333:336), 'uint32');
+clear BasicHeader;
+
+if strcmpi(NEV.MetaTags.FileTypeID, 'NEURALEV')
+    if exist([fileFullPath(1:end-8) '.sif'], 'file') == 2
+        METATAGS = textread([fileFullPath(1:end-8) '.sif'], '%s');
+        NEV.MetaTags.Subject      = METATAGS{3}(5:end-5);
+        NEV.MetaTags.Experimenter = [METATAGS{5}(8:end-8) ' ' METATAGS{6}(7:end-7)];
+    end
+end
+if ~any(strcmpi(NEV.MetaTags.FileSpec, {'2.1', '2.2', '2.3'}))
+    disp('Unknown filespec. Cannot open file.');
+    fclose FID;
+    clear variables;
+    if nargout
+        varargout{1} = [];
+    end
+    return;
+end
+clear fileFullPath;
+
+%% Parsing and validating FileSpec and DateTime variables
+NEV.MetaTags.DateTimeRaw = t.';
+NEV.MetaTags.DateTime = [num2str(t(2)) '/'  num2str(t(4)+2) '/' num2str(t(1))...
+    ' ' datestr(t(3), 'dddd') ' ' num2str(t(5)) ':'  ...
+    num2str(t(6)) ':'  num2str(t(7)) '.' num2str(t(8))] ;
+clear t;
+
+%% Removing extra garbage characters from the Comment field.
+NEV.MetaTags.Comment(find(NEV.MetaTags.Comment==0,1):end) = 0;
+
+%% Recording after BasicHeader file position
+Trackers.fBasicHeader = ftell(FID); %#ok<NASGU>
+
+% Calculating the length of the data
+currentLocation = ftell(FID);
+fseek(FID, -Trackers.countPacketBytes, 'eof');
+NEV.MetaTags.DataDuration = fread(FID, 1, 'uint32=>double');
+NEV.MetaTags.DataDurationSec = double(NEV.MetaTags.DataDuration) / double(NEV.MetaTags.SampleRes);
+fseek(FID, currentLocation, 'bof');
+
+%% Reading ExtendedHeader information
+for ii=1:Trackers.countExtHeader
+    ExtendedHeader = fread(FID, 32, '*uint8');
+    PacketID = char(ExtendedHeader(1:8)');
+    switch PacketID
+        case 'ARRAYNME'
+            NEV.ArrayInfo.ElectrodeName    = char(ExtendedHeader(9:end));
+        case 'ECOMMENT'
+            NEV.ArrayInfo.ArrayComment     = char(ExtendedHeader(9:end));
+        case 'CCOMMENT'
+            NEV.ArrayInfo.ArrayCommentCont = char(ExtendedHeader(9:end));
+        case 'MAPFILE'
+            NEV.ArrayInfo.MapFile          = char(ExtendedHeader(9:end));
+        case 'NEUEVWAV'
+            ElectrodeID                       = typecast(ExtendedHeader(9:10), 'uint16');
+            NEV.ElectrodesInfo(ElectrodeID).ElectrodeID     = ElectrodeID;
+            NEV.ElectrodesInfo(ElectrodeID).ConnectorBank   = char(ExtendedHeader(11)+64);
+            NEV.ElectrodesInfo(ElectrodeID).ConnectorPin    = ExtendedHeader(12);
+            df   = typecast(ExtendedHeader(13:14),'int16');
+            % This is a workaround for the DigitalFactor overflow in NEV 
+            % files. Remove once Central is updated
+            if df == 21516
+                NEV.ElectrodesInfo(ElectrodeID).DigitalFactor = 152592.547;
+            else
+                NEV.ElectrodesInfo(ElectrodeID).DigitalFactor = df;
+            end
+            % End of workaround
+            NEV.ElectrodesInfo(ElectrodeID).EnergyThreshold = typecast(ExtendedHeader(15:16),'uint16');
+            NEV.ElectrodesInfo(ElectrodeID).HighThreshold   = typecast(ExtendedHeader(17:18),'int16');
+            NEV.ElectrodesInfo(ElectrodeID).LowThreshold    = typecast(ExtendedHeader(19:20),'int16');
+            NEV.ElectrodesInfo(ElectrodeID).Units           = ExtendedHeader(21);
+            NEV.ElectrodesInfo(ElectrodeID).WaveformBytes   = ExtendedHeader(22);
+            clear ElectrodeID;
+        case 'NEUEVLBL'
+            ElectrodeID                       = typecast(ExtendedHeader(9:10), 'uint16');
+            NEV.ElectrodesInfo(ElectrodeID).ElectrodeLabel = char(ExtendedHeader(11:26));
+            clear ElectrodeID;
+        case 'NEUEVFLT'
+            ElectrodeID                       = typecast(ExtendedHeader(9:10), 'uint16');
+            NEV.ElectrodesInfo(ElectrodeID).HighFreqCorner = typecast(ExtendedHeader(11:14),'uint32');
+            NEV.ElectrodesInfo(ElectrodeID).HighFreqOrder  = typecast(ExtendedHeader(15:18),'uint32');
+            NEV.ElectrodesInfo(ElectrodeID).HighFilterType = typecast(ExtendedHeader(19:20),'uint16');
+            NEV.ElectrodesInfo(ElectrodeID).LowFreqCorner  = typecast(ExtendedHeader(21:24),'uint32');
+            NEV.ElectrodesInfo(ElectrodeID).LowFreqOrder   = typecast(ExtendedHeader(25:28),'uint32');
+            NEV.ElectrodesInfo(ElectrodeID).LowFilterType  = typecast(ExtendedHeader(29:30),'uint16');
+            clear ElectrodeID;
+        case 'DIGLABEL'
+            Mode                    = ExtendedHeader(25);
+            NEV.IOLabels{Mode+1}    = char(ExtendedHeader(9:24).');
+            clear Mode;
+        case 'NSASEXEV' %% Not implemented in the Cerebus firmware. 
+                        %% Needs to be updated once implemented into the 
+                        %% firmware by Blackrock Microsystems.
+            NEV.NSAS.Freq          = typecast(ExtendedHeader(9:10),'uint16');
+            NEV.NSAS.DigInputConf  = char(ExtendedHeader(11));
+            NEV.NSAS.AnalCh1Conf   = char(ExtendedHeader(12));
+            NEV.NSAS.AnalCh1Detect = typecast(ExtendedHeader(13:14),'uint16');
+            NEV.NSAS.AnalCh2Conf   = char(ExtendedHeader(15));
+            NEV.NSAS.AnalCh2Detect = typecast(ExtendedHeader(16:17),'uint16');
+            NEV.NSAS.AnalCh3Conf   = char(ExtendedHeader(18));
+            NEV.NSAS.AnalCh3Detect = typecast(ExtendedHeader(19:20),'uint16');
+            NEV.NSAS.AnalCh4Conf   = char(ExtendedHeader(21));
+            NEV.NSAS.AnalCh4Detect = typecast(ExtendedHeader(22:23),'uint16');
+            NEV.NSAS.AnalCh5Conf   = char(ExtendedHeader(24));
+            NEV.NSAS.AnalCh5Detect = typecast(ExtendedHeader(25:26),'uint16');
+        case 'VIDEOSYN'
+            cnt = 1;
+            if (isfield(NEV, 'VideoSyncInfo'))
+                cnt = size(NEV.VideoSyncInfo, 2) + 1;
+            end
+            NEV.VideoSyncInfo(cnt).SourceID     = typecast(ExtendedHeader(9:10),'uint16');
+            NEV.VideoSyncInfo(cnt).SourceName   = char(ExtendedHeader(11:26))';
+            NEV.VideoSyncInfo(cnt).FrameRateFPS = typecast(ExtendedHeader(27:30),'single')';
+            clear cnt;
+        case 'TRACKOBJ'
+            cnt = 1;
+            if (isfield(NEV, 'ObjTrackInfo'))
+                cnt = size(NEV.ObjTrackInfo, 2) + 1;
+            end
+            NEV.ObjTrackInfo(cnt).TrackableType = typecast(ExtendedHeader(9:10),'uint16');
+            NEV.ObjTrackInfo(cnt).TrackableID   = typecast(ExtendedHeader(11:14), 'uint32');
+            NEV.ObjTrackInfo(cnt).TrackableName = char(ExtendedHeader(15:30))';
+            clear cnt;
+        otherwise
+            disp(['PacketID ' PacketID ' is invalid.']);
+            disp('Please make sure this version of openNEV is compatible with your current NSP firmware.')
+            fclose(FID);
+            clear variables; 
+            if nargout
+                varargout{1} = [];
+            end
+            return;
+    end
+end
+NEV.MetaTags.ChannelID = [NEV.ElectrodesInfo.ElectrodeID];
+clear ExtendedHeader PacketID ii;
+
+%% Recording after ExtendedHeader file position and calculating Data Length
+%  and number of data packets
+fseek(FID, 0, 'eof');
+Trackers.fData = ftell(FID);
+Trackers.countDataPacket = (Trackers.fData - Trackers.fExtendedHeader)/Trackers.countPacketBytes;
+NEV.MetaTags.PacketCount = Trackers.countDataPacket;
+
+%%
+Flags.UnparsedDigitalData = 0;
+
+%% Reading packet headers and digital values
+Timestamp = [];
+PacketIDs = [];
+tempClassOrReason = [];
+tempDigiVals = [];
+if NEV.MetaTags.PacketCount ~= 0
+    fseek(FID, Trackers.fExtendedHeader, 'bof');
+    tRawData  = fread(FID, [10 Trackers.countDataPacket], '10*uint8=>uint8', Trackers.countPacketBytes - 10);
+    Timestamp = tRawData(1:4,:);
+    Timestamp = typecast(Timestamp(:), 'uint32').';
+
+    %% Calculate the number of packets that need to be read based on the time input parameters
+    if ~exist('readTime', 'var')
+        Trackers.readPackets = [1, length(Timestamp)];
+    else
+        [tmp,tempReadPackets] = find(Timestamp > readTime(1)*NEV.MetaTags.SampleRes,1,'first');
+        if ~isempty(tempReadPackets)
+            Trackers.readPackets(1) = tempReadPackets;
+        else
+            Trackers.readPackets(1) = NaN;
+        end
+        if isnan(Trackers.readPackets(1))
+            fprintf('The file contains %0.2f seconds of data. The requested begining timestamp of %0.2f seconds is longer than the duration.\n', ...
+                double(Timestamp(end))/double(NEV.MetaTags.SampleRes), ...
+                readTime(1));
+            clear variables;
+            if nargout
+                varargout{1} = [];
+            end
+            return;
+        end
+        [tmp,tempReadPackets] = find(Timestamp < readTime(2)*NEV.MetaTags.SampleRes,1,'last');
+        if ~isempty(tempReadPackets)
+            if readTime(2)*NEV.MetaTags.SampleRes > Timestamp(end)
+                fprintf('The file contains %0.2f seconds of data. The requested end duration of %0.2f seconds will be adjusted to %0.2f seconds.\n', ...
+                    double(Timestamp(end))/double(NEV.MetaTags.SampleRes), ...
+                    readTime(2),...
+                    double(Timestamp(end))/double(NEV.MetaTags.SampleRes));
+            end
+            Trackers.readPackets(2) = tempReadPackets;
+        else
+            Trackers.readPackets(2) = NaN;
+        end
+        clear tmp, tempReadPackets;
+    end
+   
+    PacketIDs = tRawData(5:6,Trackers.readPackets(1):Trackers.readPackets(2));
+    PacketIDs = typecast(PacketIDs(:), 'uint16').';
+    tempClassOrReason = uint8(tRawData(7,Trackers.readPackets(1):Trackers.readPackets(2)));
+    if strcmpi(Flags.digIOBits, '16bits')
+        tempDigiVals      = tRawData(9:10,Trackers.readPackets(1):Trackers.readPackets(2));
+        tempDigiVals      = typecast(tempDigiVals(:), 'uint16');
+    else
+        tempDigiVals      = uint16(tRawData(9,Trackers.readPackets(1):Trackers.readPackets(2)));
+    end
+    clear tRawData;
+else
+    Trackers.readPackets = zeros(1,2);
+end
+
+%% Defining PacketID constants
+digserPacketID = 0;
+neuralIndicesPacketIDBounds = [1, 16384];
+commentPacketID = 65535;
+videoSyncPacketID = 65534;
+trackingPacketID = 65533;
+patientTrigPacketID = 65532;
+reconfigPacketID = 65531;
+
+%% Parse read digital data. Please refer to help to learn about the proper
+% formatting if the data.
+digserIndices              = find(PacketIDs == digserPacketID);
+neuralIndices              = find(neuralIndicesPacketIDBounds(2) >= PacketIDs & PacketIDs >= neuralIndicesPacketIDBounds(1));
+commentIndices             = find(PacketIDs == commentPacketID);
+videoSyncPacketIDIndices   = find(PacketIDs == videoSyncPacketID);
+trackingPacketIDIndices    = find(PacketIDs == trackingPacketID);
+patientTrigPacketIDIndices = find(PacketIDs == patientTrigPacketID);
+reconfigPacketIDIndices    = find(PacketIDs == reconfigPacketID);
+clear digserPacketID neuralIndicesPacketIDBounds commentPacketID ...
+      videoSyncPacketID trackingPacketID patientTrigPacketID reconfigPacketID;
+digserTimestamp            = Timestamp(digserIndices);
+NEV.Data.Spikes.TimeStamp  = Timestamp(neuralIndices);
+NEV.Data.Spikes.Electrode  = PacketIDs(neuralIndices);
+clear PacketIDs;
+NEV.Data.Spikes.Unit       = tempClassOrReason(neuralIndices); 
+%clear neuralIndices;
+NEV.Data.SerialDigitalIO.InsertionReason   = tempClassOrReason(digserIndices);
+clear tempClassOrReason;
+DigiValues                 = tempDigiVals(digserIndices);
+clear tempDigiVals;
+
+%% Reads the waveforms if 'read' is passed to the function
+if strcmpi(Flags.ReadData, 'read')
+    allExtraDataPacketIndices  = [commentIndices, ...
+                                  videoSyncPacketIDIndices, ...
+                                  trackingPacketIDIndices, ...
+                                  patientTrigPacketIDIndices, ...
+                                  reconfigPacketIDIndices];
+      
+    if ~isempty(allExtraDataPacketIndices) % if there is any extra packets
+        fseek(FID, Trackers.fExtendedHeader, 'bof');
+        fseek(FID, (Trackers.readPackets(1)-1) * Trackers.countPacketBytes, 'cof');
+        tRawData  = fread(FID, [Trackers.countPacketBytes Trackers.readPackets(2)], ...
+            [num2str(Trackers.countPacketBytes) '*uint8=>uint8'], 0);
+        if ~isempty(commentIndices)
+            NEV.Data.Comments.TimeStamp = Timestamp(commentIndices);
+            NEV.Data.Comments.TimeStampSec = double(NEV.Data.Comments.TimeStamp)/double(NEV.MetaTags.TimeRes);
+            NEV.Data.Comments.CharSet = tRawData(7, commentIndices);
+            NEV.Data.Comments.Color = tRawData(9:12, commentIndices);
+            NEV.Data.Comments.Color = typecast(NEV.Data.Comments.Color(:), 'uint32').';
+            NEV.Data.Comments.Text  = char(tRawData(13:Trackers.countPacketBytes, commentIndices).');
+            
+            % Transferring NeuroMotive Events to its own structure
+            neuroMotiveEvents = find(NEV.Data.Comments.CharSet == 255);
+            NEV.Data.TrackingEvents.TimeStamp = NEV.Data.Comments.TimeStamp(neuroMotiveEvents);
+            NEV.Data.TrackingEvents.TimeStampSec = double(NEV.Data.TrackingEvents.TimeStamp)/double(NEV.MetaTags.TimeRes);
+            NEV.Data.TrackingEvents.Text = NEV.Data.Comments.Text(neuroMotiveEvents,:);
+            NEV.Data.Comments.TimeStamp(neuroMotiveEvents) = [];
+            NEV.Data.Comments.TimeStampSec(neuroMotiveEvents) = [];
+            NEV.Data.Comments.CharSet(neuroMotiveEvents) = [];
+            NEV.Data.Comments.Color(neuroMotiveEvents) = [];
+            NEV.Data.Comments.Text(neuroMotiveEvents) = [];
+            
+            clear commentIndices;
+        end
+        if ~isempty(videoSyncPacketIDIndices)
+            NEV.Data.VideoSync.TimeStamp       = Timestamp(videoSyncPacketIDIndices);
+            NEV.Data.VideoSync.FileNumber      = tRawData(7:8, videoSyncPacketIDIndices);
+            NEV.Data.VideoSync.FileNumber      = typecast(NEV.Data.VideoSync.FileNumber(:), 'uint16').';
+            NEV.Data.VideoSync.FrameNumber     = tRawData(9:12, videoSyncPacketIDIndices);
+            NEV.Data.VideoSync.FrameNumber     = typecast(NEV.Data.VideoSync.FrameNumber(:), 'uint32').';
+            NEV.Data.VideoSync.ElapsedTime     = tRawData(13:16, videoSyncPacketIDIndices);
+            NEV.Data.VideoSync.ElapsedTime     = typecast(NEV.Data.VideoSync.ElapsedTime(:), 'uint32').';
+            NEV.Data.VideoSync.SourceID        = tRawData(17:20, videoSyncPacketIDIndices);
+            NEV.Data.VideoSync.SourceID        = typecast(NEV.Data.VideoSync.SourceID(:), 'uint32').';
+            clear videoSyncPacketIDIndices;
+        end
+        if ~isempty(trackingPacketIDIndices)
+            tmp.TimeStamp     = Timestamp(trackingPacketIDIndices);
+            tmp.TimeStampSec  = double(tmp.TimeStamp)/30000;
+            % This portion is commented out because it does not contain any
+            % information as of yet.
+            tmp.ParentID      = tRawData(7:8, trackingPacketIDIndices);
+            tmp.ParentID      = typecast(tmp.ParentID(:), 'uint16').';
+            tmp.NodeID        = tRawData(9:10, trackingPacketIDIndices);
+            tmp.NodeID        = typecast(tmp.NodeID(:), 'uint16').';
+            tmp.NodeCount     = tRawData(11:12, trackingPacketIDIndices);
+            tmp.NodeCount     = typecast(tmp.NodeCount(:), 'uint16').';
+            tmp.MarkerCount   = tRawData(13:14, trackingPacketIDIndices);
+            tmp.MarkerCount   = typecast(tmp.MarkerCount(:), 'uint16').';
+            
+            tmp.rigidBodyPoints = tRawData(15:102, trackingPacketIDIndices);
+            tmp.rigidBodyPoints = reshape(typecast(tmp.rigidBodyPoints(:), 'uint16'), 44, length(tmp.ParentID));
+            
+            objectIndex = [0 '1' '2' '3' '4' '1' '2' '3' '4'];
+            if (isfield(NEV, 'ObjTrackInfo'))
+                for IDX = 1:size(NEV.ObjTrackInfo,2)
+                    emptyChar = find(NEV.ObjTrackInfo(IDX).TrackableName == 0, 1);
+                    NEV.ObjTrackInfo(IDX).TrackableName(emptyChar) = objectIndex(IDX);
+                    indicesOfEvent = find(tmp.NodeID == IDX-1);
+                    if ~isempty(indicesOfEvent)
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).TimeStamp = tmp.TimeStamp(indicesOfEvent);
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).TimeStampSec = tmp.TimeStampSec(indicesOfEvent);
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).ParentID =    tmp.ParentID(indicesOfEvent);
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).NodeCount =   tmp.NodeCount(indicesOfEvent);
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCount = tmp.MarkerCount(indicesOfEvent);
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCoordinates(size(NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).TimeStamp,2)).X = [];
+                        NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCoordinates(size(NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).TimeStamp,2)).X = [];
+                        for xyIDX = 1:size(NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).TimeStamp,2)
+                            NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCoordinates(xyIDX).X = ...
+                                tmp.rigidBodyPoints(1:2:NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCount(xyIDX)*2, indicesOfEvent(xyIDX));
+                            NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCoordinates(xyIDX).Y = ...
+                                tmp.rigidBodyPoints(2:2:NEV.Data.Tracking.(NEV.ObjTrackInfo(IDX).TrackableName).MarkerCount(xyIDX)*2, indicesOfEvent(xyIDX));
+                        end
+                    end
+                end
+            end
+            clear trackingPacketIDIndices tmp;
+        end
+        if ~isempty(patientTrigPacketIDIndices)
+            NEV.Data.PatientTrigger.TimeStamp    = Timestamp(patientTrigPacketIDIndices);
+            NEV.Data.PatientTrigger.TriggerType  = tRawData(7:8, patientTrigPacketIDIndices);
+            NEV.Data.PatientTrigger.TriggerType  = typecast(NEV.Data.PatientTrigger.TriggerType(:), 'uint16').';
+            clear patientTrigPacketIDIndices;
+        end
+        if ~isempty(reconfigPacketIDIndices)
+            NEV.Data.Reconfig.TimeStamp     = Timestamp(reconfigPacketIDIndices);
+            NEV.Data.Reconfig.ChangeType    = tRawData(7:8, reconfigPacketIDIndices);
+            NEV.Data.Reconfig.ChangeType    = typecast(NEV.Data.Reconfig.ChangeType(:), 'uint16').';
+            NEV.Data.Reconfig.CompName      = char(tRawData(9:24, reconfigPacketIDIndices));
+            NEV.Data.Reconfig.ConfigChanged = char(tRawData(25:Trackers.countPacketBytes, reconfigPacketIDIndices));
+            clear reconfigPacketIDIndices;
+        end
+    end % end if ~isempty(allExtraDataPacketIndices)
+
+    clear Timestamp tRawData count idx;
+      
+   % now read waveform
+    fseek(FID, Trackers.fExtendedHeader + 8, 'bof'); % Seek to location of spikes
+    fseek(FID, (Trackers.readPackets(1)-1) * Trackers.countPacketBytes, 'cof');
+    NEV.Data.Spikes.WaveformUnit = Flags.waveformUnits;
+    NEV.Data.Spikes.Waveform = fread(FID, [(Trackers.countPacketBytes-8)/2 Trackers.readPackets(2)], ...
+        [num2str((Trackers.countPacketBytes-8)/2) '*int16=>int16'], 8);
+    NEV.Data.Spikes.Waveform(:, [digserIndices allExtraDataPacketIndices]) = []; 
+
+    clear allExtraDataPacketIndices;
+    if strcmpi(Flags.waveformUnits, 'uv')
+        elecDigiFactors = double(1000./[NEV.ElectrodesInfo(NEV.Data.Spikes.Electrode).DigitalFactor]);
+        NEV.Data.Spikes.Waveform = bsxfun(@rdivide, double(NEV.Data.Spikes.Waveform), elecDigiFactors);
+        if strcmpi(Flags.WarningStat, 'warning')
+            fprintf(1,'\nThe spike waveforms are in unit of uV.\n');
+            fprintf(2,'WARNING: This conversion may lead to loss of information.');
+            fprintf(1,'\nRefer to help for more information.\n');
+        end
+    end
+end
+clear digserIndices;
+
+%% Parse digital data if requested
+if ~isempty(DigiValues)
+    if strcmpi(Flags.ParseData, 'parse')
+        try
+            DigiValues = char(DigiValues);
+            Inputs                     = {'Digital'; 'AnCh1'; 'AnCh2'; 'AnCh3'; 'AnCh4'; 'AnCh5'; 'PerSamp'; 'Serial'};
+            AsteriskIndices   = find(DigiValues == '*');
+            DataBegTimestamp = digserTimestamp(AsteriskIndices);
+            splitDigiValues = regexp(DigiValues(2:end), '*', 'split')';
+            for idx = 1:length(splitDigiValues)
+                try
+                    if isempty(find(splitDigiValues{idx} == ':', 1))
+                        splitDigiValues{idx}(find(splitDigiValues{idx} == '#')) = [];
+                        NEV.Data.SerialDigitalIO(idx).Value = splitDigiValues{idx};
+                        NEV.Data.SerialDigitalIO(idx).Type = 'Marker';
+                    else
+                        [tempParsedCommand error] = parseCommand(splitDigiValues{idx});
+                        if ~error
+                            pcFields = fields(tempParsedCommand);
+                            NEV.Data.SerialDigitalIO(idx).Value = splitDigiValues{idx};
+                            for fidx = 1:length(pcFields)
+                                NEV.Data.SerialDigitalIO(idx).(pcFields{fidx}) = tempParsedCommand.(pcFields{fidx});
+                            end
+                        else
+                            NEV.Data.SerialDigitalIO(idx).Value = splitDigiValues{idx};
+                            NEV.Data.SerialDigitalIO(idx).Type = 'UnparsedData';
+                            Flags.UnparsedDigitalData = 1;
+                        end
+                    end
+                catch
+                    disp(['Error parsing: ' splitDigiValues{idx}]);
+                    disp('Please refer to the help for more information on how to properly format the digital data for parsing.');
+                end
+            end
+            % Populate the NEV structure with Timestamp and inputtypes for the
+            % digital data
+            if ~isempty(DataBegTimestamp)
+                c = num2cell(DataBegTimestamp); [NEV.Data.SerialDigitalIO(1:length(NEV.Data.SerialDigitalIO)).TimeStamp] = deal(c{1:end});
+                c = num2cell(DataBegTimestamp/NEV.MetaTags.SampleRes); [NEV.Data.SerialDigitalIO.TimeStampSec] = deal(c{1:end});
+                c = {Inputs{NEV.Data.SerialDigitalIO.InsertionReason(AsteriskIndices)}}; [NEV.Data.SerialDigitalIO.InputType] = deal(c{1:end});
+            end
+            clear Inputs DigiValues digserTimestamp;
+        catch
+            disp(lasterr);
+            disp('An error occured during reading digital data. This is due to a problem with formatting digital data.');
+            disp('Refer to help ''help openNEV'' for more information on how to properly format the digital data.');
+            disp('Try using openNEV with ''noparse'', i.e. openNEV(''noparse'').');
+        end
+    else
+        NEV.Data.SerialDigitalIO.TimeStamp = digserTimestamp;
+        NEV.Data.SerialDigitalIO.TimeStampSec = double(digserTimestamp)/30000;
+        clear digserTimestamp;
+        NEV.Data.SerialDigitalIO.UnparsedData = DigiValues;
+        clear DigiValues;
+    end
+else
+    if strcmpi(Flags.ReadData, 'read')
+        if strcmpi(Flags.Report, 'report')
+            disp('No digital data to read.');
+        end
+    end
+end
+
+if strcmpi(Flags.ParseData, 'parse')
+    if Flags.UnparsedDigitalData && strcmpi(Flags.WarningStat, 'warning')
+        fprintf(2, 'WARNING: The NEV file contains unparsed digital data.\n');
+    end
+end
+
+%% Show a report if 'report' is passed as an argument
+if strcmpi(Flags.Report, 'report')
+    % Displaying report
+    disp( '*** FILE INFO **************************');
+    disp(['File Name           = ' NEV.MetaTags.Filename]);
+    disp(['Filespec            = ' NEV.MetaTags.FileSpec]);
+    disp(['Data Duration (min) = ' num2str(round(NEV.MetaTags.DataDuration/NEV.MetaTags.SampleRes/60))]);
+    disp(['Packet Counts       = ' num2str(Trackers.countDataPacket)]);
+    disp(' ');
+    disp( '*** BASIC HEADER ***********************');    
+    disp(['Sample Resolution   = ' num2str(NEV.MetaTags.SampleRes)]);
+    disp(['Date and Time       = '         NEV.MetaTags.DateTime]);
+    disp(['Comment             = '         NEV.MetaTags.Comment(1:64)   ]);
+    disp(['                      '         NEV.MetaTags.Comment(65:128) ]);
+    disp(['                      '         NEV.MetaTags.Comment(129:192)]);
+    disp(['                      '         NEV.MetaTags.Comment(193:256)]);
+    disp(['The load time was for NEV file was ' num2str(toc, '%0.1f') ' seconds.']);
+end
+
+%% Saving the NEV structure as a MAT file for easy access
+if strcmpi(Flags.SaveFile, 'save')
+    if exist(matPath, 'file') == 2 && strcmpi(Flags.Overwrite, 'nooverwrite')
+        disp(['File ' matPath ' already exists.']);
+        overWrite = input('Would you like to overwrite (Y/N)? ', 's');
+        if strcmpi(overWrite, 'y')
+            disp('Saving MAT file. This may take a few seconds...');
+            save(matPath, 'NEV', '-v7.3');
+        else
+            disp('File was not overwritten.');
+        end
+    elseif exist(matPath, 'file') == 2 && strcmpi(Flags.Overwrite, 'overwrite')        
+        disp(['File ' matPath ' already exists.']);
+        disp('Overwriting the old MAT file. This may take a few seconds...');
+        save(matPath, 'NEV', '-v7.3');        
+    else
+        disp('Saving MAT file. This may take a few seconds...');
+        save(matPath, 'NEV', '-v7.3');
+    end
+    clear overWrite;
+end
+
+if ~nargout
+    assignin('base', 'NEV', NEV);
+else
+    varargout{1} = NEV;
+end
+
+fclose(FID);
+clear Flags Trackers FID matPath;

+ 646 - 0
code/matlab_scripts/NPMK/NEV Utilities/saveNEV.m

@@ -0,0 +1,646 @@
+function saveNEV(NEV, varargin)
+
+%% 
+% Save an .NEV file from an NEV structure (gained by using openNEV)
+% Works with file spec 2.3
+% 
+% Use saveNEV(NEV, filename, noreport)
+
+% All input arguments are optional. Input arguments can be in any order.
+%
+%   NEV:        Name of the NEV structure to be saved.
+%               DEFAULT: The workspace NEV structure in the workspace will
+%               be saved.
+%
+%   filename:   Name of the new NEV file name.
+%               DEFAULT: -out.nev will be added to the end of the current
+%               file name.
+%
+%   'noreport': Will not display status reports or warnings.
+%               DEFAULT: will display status reports and warnings.
+%
+%
+%   OUTPUT:     None
+%
+%   Example 1: 
+%   saveNEV
+%
+%   In the example above, a new file containing the NEV structure in the
+%   workspace will be saved. The file name will have -out.NEV added to its
+%   name. Statuses of the progress of saveNEV and also warnings about the
+%   risks of saving will be displayed.
+%
+%   Example 2:
+%   openNSx(NEV, 'myNewNEVFile.nev', 'noreport');
+%
+%   In the example above, a new file containing the NEV structure in the
+%   workspace will be saved. The file name will be myNewNEVFile.nev. 
+%   Statuses of the progress of saveNEV and also warnings about the
+%   risks of saving will be not be displayed.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Nick Halper
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Version History
+%
+% 1.0.0.0: Nick Halper
+%   - Initial release.
+%
+% 1.1.0.0: Kian Torab
+%   - Added the ability to suppress the fiel saving warning with
+%     'noreport' input parameter.
+%   - Re-structured help to better match the suite's style. Added examples.
+%   - Added the 'noreport' key to supress statuses and warnings.
+%   - Improved error checking for input arguments.
+%
+% 1.2.0.0: Nick Halper - 19/8/29
+%   - Allows saveNEV to dynamically determine header offset and total
+%   number of extended headers instead of relying on info in MetaTags/Raw
+%   Data of NEV structure.
+%   - Fixed a bug where choosing to overwrite would crash the script
+%   - Fixed an issue where bank letters were not being written correctly, writing
+%   blank values
+%   - Modified the script to work with 256 channel files
+%
+% 1.3.0.0: Stephen hou - 19/8/30
+%   - Implemented saving of files that contain NeuroMotive/tracking data
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Verify FilePath and establish overwrite paramaters
+if not(NEV.MetaTags.FileSpec == '2.3')
+    disp(strcat('This function only functions on file spec 2.3,;this is your file spec:',NEV.MetaTags.FileSpec));
+    return
+end
+
+if nargin > 1
+    for idx = 1:nargin-1
+        if strcmpi(varargin{idx}, 'noreport')
+            reportFlag = 0;
+        elseif length(varargin{idx})>3 && ...
+                (strcmpi(varargin{idx}(3),'\') || ...
+                 strcmpi(varargin{idx}(1),'/') || ...
+                 strcmpi(varargin{idx}(2),'/') || ...
+                 strcmpi(varargin{idx}(1:2), '\\')) 
+            FilePath = varargin{1};
+        end
+    end
+end
+
+% Validating input arguments
+if ~exist('FilePath',   'var'); FilePath = [fullfile(NEV.MetaTags.FilePath,NEV.MetaTags.Filename) '-out.nev']; end
+if ~exist('reportFlag', 'var'); reportFlag = 1; end;
+
+% Warning user about the consequences of the modified NEV file
+if reportFlag
+    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');
+    if ~strcmpi(Accept,'y')
+        disp('Ending Script...');
+        return
+    end
+end
+
+% Validating and opening the writable file
+if exist(FilePath)
+    
+        if exist(FilePath)
+         
+                disp('File already exists!');
+                OverwritePrompt = 'y';
+                if strcmpi(OverwritePrompt,'y')
+                    Overwrite = 1;
+                    delete(FilePath);
+                else
+                    while exist(FilePath)
+                        ExistCount = ExistCount + 1;
+                        FilePath = fullfile(NEV.MetaTags.FilePath,[NEV.MetaTags.Filename '-Aligned-',num2str(ExistCount),NEV.MetaTags.FileExt]);
+                    end
+                    
+                end
+            
+        end
+end
+
+FileID = fopen(FilePath, 'w', 'ieee-le');
+    
+if (FileID <= 0)
+    disp('No file was selected.');
+    return;
+end
+
+%% Write the basic header into the file
+
+% General warining about the length of time it takes to save a NEV file so
+% the user does not abort the process
+disp(['Saving NEV file ' FilePath '. This can take a long time. Please be patient.']);
+
+if reportFlag; disp('Writing Basic Header...'); end
+
+fwrite(FileID,NEV.MetaTags.FileTypeID(1:8));
+fwrite(FileID, [str2double(NEV.MetaTags.FileSpec(1)) str2double(NEV.MetaTags.FileSpec(3))], 'uint8');
+fwrite(FileID,str2double(NEV.MetaTags.Flags),'uint16');
+fwrite(FileID,NEV.MetaTags.HeaderOffset,'uint32');
+fwrite(FileID,NEV.MetaTags.PacketBytes,'uint32');
+fwrite(FileID,NEV.MetaTags.SampleRes,'uint32');
+fwrite(FileID,NEV.MetaTags.TimeRes,'uint32');
+fwrite(FileID,NEV.MetaTags.DateTimeRaw,'uint16');
+fwrite(FileID,'saveNEV$version1001$$$$$$$$$$$$$'); 
+fwrite(FileID,NEV.MetaTags.Comment); 
+ExtendedHeaderBytes = NEV.MetaTags.HeaderOffset-ftell(FileID)+4;
+fwrite(FileID,ExtendedHeaderBytes/32,'uint32');
+
+EndOfBasicHeader = ftell(FileID);
+
+%%
+% Write the extended header into the file. 
+
+%Handling packets with array information
+if isfield(NEV,'ArrayInfo')
+    if reportFlag; disp('Writing Array Header...'); end
+    if isfield(NEV.ArrayInfo,'ElectrodeName')
+        fwrite(FileID,'ARRAYNME');
+        fwrite(FileID,NEV.ArrayInfo.ElectrodeName); %Must null terminate
+    end
+    if isfield(NEV.ArrayInfo,'ArrayComment')
+        fwrite(FileID,'ECOMMENT');
+        fwrite(FileID,NEV.ArrayInfo.ArrayComment); %Must null terminate
+    end
+    if isfield(NEV.ArrayInfo,'ArrayCommentCont')
+        fwrite(FileID,'CCOMMENT');
+        fwrite(FileID,NEV.ArrayInfo.ArrayCommentCont); %Must null terminate
+    end
+    if isfield(NEV.ArrayInfo,'MapFile')
+        fwrite(FileID,'MAPFILE'); %+NULL
+        fwrite(FileID,NEV.ArrayInfo.MapFile); %Must null terminate
+    end
+end
+
+if isfield(NEV,'ElectrodesInfo')
+    if reportFlag; disp('Writing Electrode Header...'); end
+    if (isfield(NEV.ElectrodesInfo(1),'ElectrodeID'))
+        
+    %Find length of electrode count, loop through for that count and fill
+    %in  NEUEVWAV packets. 
+        for IDX = 1:length(NEV.ElectrodesInfo)
+            Before = ftell(FileID);
+            fwrite(FileID,'NEUEVWAV');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).ElectrodeID,'uint16');
+            
+
+            %fwrite(FileID,NEV.ElectrodesInfo(IDX).ConnectorBank);
+            switch NEV.ElectrodesInfo(IDX).ConnectorBank
+                case 'A'
+                    fwrite(FileID,1,'uint8');
+                case 'B'
+                    fwrite(FileID,2,'uint8');
+                case 'C'
+                    fwrite(FileID,3,'uint8');
+                case 'D'
+                    fwrite(FileID,4,'uint8');
+                case 'E'
+                    fwrite(FileID,5,'uint8');
+                case 'F'
+                    fwrite(FileID,6,'uint8');
+                case 'G'
+                    fwrite(FileID,7,'uint8');
+                case 'H'
+                    fwrite(FileID,8,'uint8');
+                case 'I'
+                    fwrite(FileID,9,'uint8');
+            end
+        
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).ConnectorPin,'uint8');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).DigitalFactor,'uint16');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).EnergyThreshold,'uint16');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).HighThreshold,'int16');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).LowThreshold,'int16');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).Units,'uint8');
+            fwrite(FileID,NEV.ElectrodesInfo(IDX).WaveformBytes,'uint8');
+            if isempty(NEV.Data.Spikes.Waveform)
+                fwrite(FileID,48,'uint16');
+                SpikeLength = 48;
+            else
+                fwrite(FileID,length(NEV.Data.Spikes.Waveform(:,1)),'uint16');
+                SpikeLength = length(NEV.Data.Spikes.Waveform(:,1));
+            end
+            %if file type is 2.2, don't need previous field and end in 10
+            %zeros
+            fwrite(FileID,zeros(8,1),'uint8');
+            After = ftell(FileID);
+            if After-Before ~= 32
+                disp('Broken Electrode Info')
+                NEV.ElectrodesInfo(IDX).ConnectorBank
+            end
+        end
+    end
+    if (isfield(NEV.ElectrodesInfo(1),'ElectrodeLabel'))
+        for IDX = 1:length(NEV.ElectrodesInfo)
+        Before = ftell(FileID);
+        fwrite(FileID,'NEUEVLBL');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).ElectrodeID,'uint16');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).ElectrodeLabel);%Must be nulll terminated
+        fwrite(FileID, zeros(6,1),'uint8');
+        After = ftell(FileID);
+        if After-Before ~= 32
+            disp('Broken Electrode Label')
+        end
+        end
+    end
+    if (isfield(NEV.ElectrodesInfo(1),'HighFreqCorner'))
+        for IDX = 1:length(NEV.ElectrodesInfo)
+        Before = ftell(FileID);
+        fwrite(FileID,'NEUEVFLT');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).ElectrodeID,'uint16');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).HighFreqCorner,'uint32');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).HighFreqOrder,'uint32');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).HighFilterType,'uint16');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).LowFreqCorner,'uint32');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).LowFreqOrder,'uint32');
+        fwrite(FileID, NEV.ElectrodesInfo(IDX).LowFilterType,'uint16');
+        fwrite(FileID, zeros(2,1), 'uint8');
+        After = ftell(FileID);
+        if After-Before ~= 32
+            disp('Broken High Freq Corner');
+        end
+        end
+    end   
+end
+%Digital inputs
+if isfield(NEV,'IOLabels')
+    if reportFlag; disp('Writing IOLabels Header...'); end
+        for IDX = 1:length(NEV.IOLabels)
+            Before = ftell(FileID);
+            fwrite(FileID,'DIGLABEL');
+            fwrite(FileID,'Serial1XXXXXXXXX','uint8');
+            fwrite(FileID, IDX - 1, 'uint8');
+            fwrite(FileID, zeros(7,1),'uint8');
+            After = ftell(FileID);
+            if After-Before ~= 32
+               disp('Broken IO Labels');
+            end
+        end
+end
+    
+%Video Packets
+if isfield(NEV,'VideoSyncInfo')
+    if reportFlag; disp('Writing Video Header...'); end
+    for IDX = 1:length(NEV.VideoSyncInfo)
+    Before = ftell(FileID);
+    fwrite(FileID,'VIDEOSYN');
+    fwrite(FileID, NEV.VideoSyncInfo(IDX).SourceID, 'uint16');
+    fwrite(FileID, NEV.VideoSyncInfo(IDX).SourceName(1:16));
+    fwrite(FileID, NEV.VideoSyncInfo(IDX).FrameRateFPS,'single');
+    fwrite(FileID, zeros(2,1),'uint8');
+    After = ftell(FileID);
+    if After-Before ~= 32
+       disp('Broken Video Sync Info');
+       PacketNumber = IDX;
+       TotalPackets = length(NEV.VideoSyncInfo);
+    end
+    end
+end
+
+if isfield(NEV,'NSAS')
+    %This might exist in a future version of Central
+end
+
+if isfield(NEV,'ObjTrackInfo')
+    if reportFlag; disp('Writing Tracking Header...'); end
+    for IDX = 1:length(NEV.ObjTrackInfo)
+    Before = ftell(FileID);
+    fwrite(FileID,'TRACKOBJ');
+    fwrite(FileID, NEV.ObjTrackInfo(IDX).TrackableType,'uint16');
+    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.
+    NEV.ObjTrackInfo(IDX).TrackableName = pad(NEV.ObjTrackInfo(IDX).TrackableName,16,'X'); 
+    fwrite(FileID, NEV.ObjTrackInfo(IDX).TrackableName);
+    fwrite(FileID, zeros(2,1),'uint8');
+    After = ftell(FileID);
+    if After-Before ~= 32
+       disp('Broken Obj Track Info');
+    end
+    end
+end
+
+if isfield(NEV,'Rabbits')
+    %Fill in the details about Rabbits at some point in the future.
+end
+
+EndOfExtendedHeader = ftell(FileID);
+
+%% Edit the Basic Header to Account for Number of Extended Headers
+
+fseek(FileID,12,'bof');
+fwrite(FileID,EndOfExtendedHeader,'uint32');
+fseek(FileID,322,'bof');
+fwrite(FileID,(EndOfExtendedHeader-EndOfBasicHeader)/32,'uint32');
+fseek(FileID,EndOfExtendedHeader,'bof');
+
+
+%%
+% Write Data
+BytesInPackets = NEV.MetaTags.PacketBytes;
+Broken = 0;
+
+%SerialDigitalIO CHECK
+if ~isempty(NEV.Data.SerialDigitalIO.TimeStamp)
+    if reportFlag; disp('Writing Serial/Digital Data...'); end
+    for IDX = 1:length(NEV.Data.SerialDigitalIO.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.SerialDigitalIO.TimeStamp(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, 0,'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.SerialDigitalIO.InsertionReason(IDX));
+        %ftell(FileID)-Before
+        fwrite(FileID, '0');
+        %ftell(FileID)-Before
+        if ~isempty(NEV.Data.SerialDigitalIO.Value)
+            fwrite(FileID, NEV.Data.SerialDigitalIO.Value(IDX),'uint16');
+        else
+            fwrite(FileID, NEV.Data.SerialDigitalIO.UnparsedData(IDX),'uint16');
+        end
+        %ftell(FileID)-Before
+        fwrite(FileID, zeros(BytesInPackets-10,1),'uint8');
+        %ftell(FileID)-Before
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+            %After-Before
+            %CurrentPacket = IDX
+            %TotalPackets = length(NEV.Data.SerialDigitalIO.TimeStamp)
+        end
+    end
+    if Broken == 1
+        disp('Serial Digital Packet Corrupted');
+        Broken = 0;
+    end
+end
+
+%Spikes CHECK
+if ~isempty(NEV.Data.Spikes.TimeStamp)
+    if reportFlag; disp('Writing Spike Data...'); end
+    for IDX = 1:length(NEV.Data.Spikes.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.Spikes.TimeStamp(IDX),'uint32');
+
+        fwrite(FileID, NEV.Data.Spikes.Electrode(IDX),'uint16');
+
+        fwrite(FileID, NEV.Data.Spikes.Unit(IDX),'uchar');
+
+        fwrite(FileID, 0,'uchar');
+
+        fwrite(FileID, NEV.Data.Spikes.Waveform(:,IDX)','int16');
+        
+        
+        
+        %for Value = 1:SpikeLength
+        %    fwrite(FileID, NEV.Data.Spikes.Waveform(Value,IDX),'int16');
+        %end
+        
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+        end
+    end
+    if Broken == 1
+        disp('Spike Packet Corrupted')
+        Broken = 0;
+    end
+end
+%disp('done')
+%Comments CHECK
+if ~isempty(NEV.Data.Comments.TimeStamp)
+    if reportFlag; disp('Writing Comment Data...'); end
+    for IDX = 1:length(NEV.Data.Comments.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.Comments.TimeStamp(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, 65535, 'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.Comments.CharSet(IDX),'uint8');
+        %ftell(FileID)-Before
+        fwrite(FileID, 0,'uint8');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.Comments.Color(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.Comments.Text(IDX,:));
+        %ftell(FileID)-Before
+        %Need to handle extra characters here etc
+        fwrite(FileID, zeros(BytesInPackets-(ftell(FileID)-Before),1),'uint8');
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+            %After-Before
+            %CurrentPacket = IDX
+            %TotalPackets = length(NEV.Data.Comments.TimeStamp)
+        end
+    end
+    if Broken == 1
+        disp('Comment Packet Corrupted')
+        Broken = 0;
+    end
+end
+
+if ~isempty(NEV.Data.TrackingEvents.TimeStamp)
+    if reportFlag; disp('Writing Tracking Event Data'); end
+    for IDX = 1:length(NEV.Data.TrackingEvents.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.TrackingEvents.TimeStamp(IDX),'uint32');
+        fwrite(FileID, 65535,'uint16');
+        fwrite(FileID, 255, 'uint8');
+        %fwrite(FileID,  2, 'uint8');
+        fwrite(FileID, 0, 'uint8'); %placeholder until I ask hyrum what the Nreuromotive flag is
+        fwrite(FileID, int2str(NEV.Data.TrackingEvents.ROINum(IDX)),'uint8');
+        %byte 1 is ROI #, byte 2 is enter or exit -- is it 1 and 2?
+        if strcmp(NEV.Data.TrackingEvents.Event(IDX),'Enter')
+            fwrite(FileID, 1,'uint8');
+        elseif strcmp(NEV.Data.TrackingEvents.Event(IDX),'Exit')
+            fwrite(FileID, 2,'uint8');
+        end
+        fwrite(FileID, zeros(2,1), 'uint8');
+        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'));
+        fwrite(FileID, zeros(BytesInPackets-(ftell(FileID)-Before),1),'uint8');
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+            %After-Before
+            %CurrentPacket = IDX
+            %TotalPackets = length(NEV.Data.Comments.TimeStamp)
+        end
+    end
+    if Broken == 1
+        disp('Tracking Event Packet Corrupted')
+        Broken = 0;
+    end
+end
+
+if ~isempty(NEV.Data.VideoSync.TimeStamp)
+    if reportFlag; disp('Writing VideoSync Data...'); end
+    for IDX = 1:length(NEV.Data.VideoSync.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.VideoSync.TimeStamp(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, 65534, 'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.VideoSync.FileNumber(IDX),'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.VideoSync.FrameNumber(IDX),'uint32');%Wrong Size
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.VideoSync.ElapsedTime(IDX),'uint32');%Wrong Size
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.VideoSync.SourceID(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, zeros(BytesInPackets - 20,1),'uint8');
+        %ftell(FileID)-Before
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+            %After-Before
+            %CurrentPacket = IDX
+            %TotalPackets = length(NEV.Data.VideoSync.TimeStamp)
+        end
+        
+    end
+    if Broken == 1
+        disp('Video Sync Packet Corrupted')
+        Broken = 0;
+    end
+end
+
+if ~isempty(NEV.Data.Tracking)
+    if reportFlag; disp('Writing Tracking Data...'); end
+    TrackingFieldNames = fieldnames(NEV.Data.Tracking);
+        for TrackingField = 1:numel(TrackingFieldNames)
+            for IDX = 1:length(NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).TimeStamp)
+                Before = ftell(FileID);
+                if NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCount == 0
+                    
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).TimeStamp(IDX),'uint32');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, 65533, 'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).ParentID(IDX),'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, TrackingField-1,'uint16'); %Node ID
+                    %ftell(FileID)-Before                    
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).NodeCount(IDX),'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCount(IDX),'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, zeros(2,1),'uint8');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, zeros(BytesInPackets - 16,1),'uint8');
+      
+                else
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).TimeStamp(IDX),'uint32');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, 65533, 'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).ParentID(IDX),'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, TrackingField-1,'uint16'); %Node ID
+                    %ftell(FileID)-Before
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).NodeCount(IDX),'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCount(IDX),'uint16');
+                    %ftell(FileID)-Before
+                    MarkerCoordinatesBytes = length(NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCoordinates(IDX).X);
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCoordinates(IDX).X,'uint16');
+                    %ftell(FileID)-Before
+                    fwrite(FileID, NEV.Data.Tracking.(TrackingFieldNames{TrackingField}).MarkerCoordinates(IDX).Y,'uint16');
+
+                    %ftell(FileID)-Before
+                    if MarkerCoordinatesBytes == 1
+                        fwrite(FileID, zeros(BytesInPackets - 14-MarkerCoordinatesBytes*4,1),'uint8');
+                    else
+                        fwrite(FileID, zeros(BytesInPackets - 14-MarkerCoordinatesBytes*4,1),'uint8');
+                    end
+                end
+                    
+                After = ftell(FileID);
+                if After-Before ~= BytesInPackets
+                    Broken = 1;
+                    %After-Before
+                    %CurrentPacket = IDX
+                    %TotalPackets = length(NEV.Data.VideoSync.TimeStamp)
+                end
+                %Must somehow terminate in correct number of zeros
+            end
+            if Broken == 1
+                disp('Tracking Packet Corrupted')
+                disp(After - Before)
+                Broken = 0;
+            end
+        end
+end
+
+if ~isempty(NEV.Data.PatientTrigger.TimeStamp)
+    if reportFlag; disp('Writing Patient Trigger Data...'); end
+    for IDX = 1:length(NEV.Data.PatientTrigger.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.PatientTrigger.TimeStamp(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, 65532, 'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.PatientTrigger.TriggerType(IDX),'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, zeros(BytesInPackets - 8, 1),'uint8');
+        %ftell(FileID)-Before
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+            %After-Before
+            %CurrentPacket = IDX
+            %TotalPackets = length(NEV.Data.PatientTrigger.TimeStamp)
+        end
+    end
+    if Broken == 1
+        disp('Patient Trigger Packet Corrupted')
+        Broken = 0;
+    end
+    
+end
+
+if ~isempty(NEV.Data.Reconfig.TimeStamp)
+    if reportFlag; disp('Writing Reconfig Data...'); end
+    for IDX = 1:length(NEV.Data.Reconfig.TimeStamp)
+        Before = ftell(FileID);
+        fwrite(FileID, NEV.Data.Reconfig.TimeStamp(IDX),'uint32');
+        %ftell(FileID)-Before
+        fwrite(FileID, 65531, 'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, NEV.Data.Reconfig.ChangeType(IDX),'uint16');
+        %ftell(FileID)-Before
+        fwrite(FileID, zeros(BytesInPackets - 8,1),'uint8');
+        %ftell(FileID)-Before
+        After = ftell(FileID);
+        if After-Before ~= BytesInPackets
+            Broken = 1;
+            %After-Before
+            %CurrentPacket = IDX
+            %TotalPackets = length(NEV.Data.Reconfig.TimeStamp)
+        end
+    end
+    if Broken == 1
+        disp('Reconfig Packet Corrupted')
+        Broken = 0;
+    end
+end
+
+if reportFlag; disp('Finished!'); end
+
+clear After
+clear Before
+clear Broken
+clear BytesInPackeets
+clear ExtendedHederBytes
+clear FilePath
+clear IDX
+clear SpikeLength
+clear Value
+
+fclose('all');
+

+ 137 - 0
code/matlab_scripts/NPMK/NEV Utilities/saveNEVSpikes.m

@@ -0,0 +1,137 @@
+function saveNEVSpikes(spikeStruct, newFileName)
+
+% saveNEVSpikes
+% 
+% Allows the user to save a modified version of the spike waveforms into a 
+% NEV file. This can be very useful for those who want to save MATLAB
+% sorted or rethresholded NEV data back into the NEV file. It also re-saves
+% the other data in the original NEV file into the new NEV. A
+%
+% Use saveNEVSpikes(spikeStruct, newFileName)
+%
+%   spikeStruct: The structure containing the spike data needed to be
+%                saved. The structure format must match the one that 
+%                openNEV outputs.
+%                spikeStruct.TimeStamp: contains all the timestamps
+%                spikeStruct.Electrode: contains all the electrode #s
+%                spikeStruct.Unit: contains all the sorted unit #s
+%                spikeStruct.Waveform: Spike waveforms, containing 48 data
+%                                      points
+%
+%   newFileName: The file name of the new NEV file.
+%                DEFAULT: User will be prmpted for a file name.
+%
+%   Example 1:
+%   saveNEVSpikes(spikeStruct, 'sortedNEV';
+%
+%   In the example above, the user will be prompted to select a NEV file.
+%   The data stored in spikeStruct will be saved into sortedNEV alongside 
+%   the data in the user-selected NEV file. The new NEV will be saved as
+%   sortedNEV.nev
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.2.1.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: Initial Release.
+%
+% 1.2.0.0:
+%   - Fixed a bug where the data saved incorrectly under the Windows OS.
+%   - Sped up the processing significantly.
+%
+% 1.2.1.0
+%   - Fixed a bug introduced in 1.2.0.0.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Validating the input argument
+if ~exist('spikeStruct', 'var')
+    disp('spikeStruct is a required input argument.');
+    return;
+end
+
+% if isfield(spikeStruct, 'Data') && isfield(spikeStruct, 'MetaTags')
+%     newFileName = fullfile(NEV.MetaTags.FilePath, [NEV.MetaTags.Filename, '.nev']);
+%     spikeStruct = NEV.Data.Spikes;
+% end
+
+if ~exist('newFileName', 'var')
+    newFileName = input('What file name would you like to use to save the new NEV? ', 's');
+    if isempty(newFileName)
+        disp('A filename is required.');
+        return;
+    end
+end
+
+%% Opening the file and reading header
+[dataFilename dataFolder] = getFile('*.nev', 'Choose a NEV that you would like to modify.');
+fileFullPath = [dataFolder dataFilename];
+FID = fopen(fileFullPath, 'r', 'ieee-le');
+
+%% Calculating the header bytes
+BasicHeader = fread(FID, 20, '*uint8');
+headerBytes  = double(typecast(BasicHeader(13:16), 'uint32'));
+dataPacketByteLength = double(typecast(BasicHeader(17:20), 'uint32'));
+
+%% Calculating the data file length and eeking to the beginning of the file
+fseek(FID, 0, 'eof');
+endOfDataByte = ftell(FID);
+dataByteLength = endOfDataByte - headerBytes;
+numberOfPackets = double(dataByteLength) / double(dataPacketByteLength);
+
+%% Reading the header binaries and saving it for future
+fseek(FID, 0, 'bof');
+headerBinaries = fread(FID, headerBytes, '*uint8');
+
+%% Reading the data binaries
+dataBinaries = fread(FID, [dataPacketByteLength numberOfPackets], '*uint8', 0);
+
+%% Finding what PacketIDs have the desired channels
+PacketIDs = zeros(1,size(dataBinaries,2));
+for IDX = 1:size(dataBinaries,2)
+    PacketIDs(IDX) = typecast(dataBinaries(5:6, IDX), 'uint16');
+end
+
+%% Only capturing all the binary lines that contain non-spike events, such
+% as comments, tracking, patient trigger, etc.
+newDataBinaries = dataBinaries(:, PacketIDs > 256); clear dataBinaries;
+
+%% Extracting the timestamps of all the above non-spike events
+dataTimestamps = zeros(1,size(newDataBinaries,2));
+for IDX = 1:size(newDataBinaries,2)
+    dataTimestamps(IDX) = typecast(newDataBinaries(1:4, IDX), 'uint32');
+end
+
+%% Converting all the user supplied data into binaries for saving into the
+% new structure
+newSpikesBinary = zeros(size([typecast(uint32(spikeStruct.TimeStamp(1)), 'uint8'),...
+                         typecast(uint16(spikeStruct.Electrode(1)), 'uint8'),...
+                         typecast(uint8(spikeStruct.Unit(1)), 'uint8'),...
+                         1,...
+                         typecast(int16(spikeStruct.Waveform(:,1))', 'uint8')]',1), size(spikeStruct.Electrode,2));
+for idx = 1:size(spikeStruct.Electrode,2)
+    newSpikesBinary(:,idx) = [typecast(uint32(spikeStruct.TimeStamp(idx)), 'uint8'),...
+                         typecast(uint16(spikeStruct.Electrode(idx)), 'uint8'),...
+                         typecast(uint8(spikeStruct.Unit(idx)), 'uint8'),...
+                         1,...
+                         typecast(int16(spikeStruct.Waveform(:,idx))', 'uint8')]';
+end
+
+%% Processing data
+% Concatinating the user supplied data (non-spike) and the user supplied data
+newDataBinaries = [newDataBinaries, newSpikesBinary];
+
+% Ranking the spike and re-ranking the data for saving (timestamp descending)
+allTimestamps = [dataTimestamps, spikeStruct.TimeStamp];
+[~, ranking] = sort(allTimestamps);
+newDataBinaries = newDataBinaries(:,ranking);
+
+%% Saving the new NEV containig the desired channels
+FIDw = fopen([dataFolder newFileName '.nev'], 'w+', 'ieee-le');
+fwrite(FIDw, headerBinaries, 'uint8');
+fwrite(FIDw, newDataBinaries, 'uint8');
+fclose(FID);
+fclose(FIDw);

+ 129 - 0
code/matlab_scripts/NPMK/NEV Utilities/saveNEVSubSpikes.m

@@ -0,0 +1,129 @@
+function saveNEVSubSpikes(channelsToRead, fileFullPath, addedSuffix)
+
+% saveNEVSubSpikes
+% 
+% Opens saves a new NEV file that only contains chanenls in channelsToRead.
+%
+% Use saveNEVSubSpikes(channelsToRead)
+%
+%   channelsToRead: The channel data to be saved into a new NEV.
+%                   DEFAULT: This input is required.
+%
+%   fileFullPath:   The full path to the NEV file that is going to be
+%                   used for splitting.
+%                   DEFAULT: The user will be prompted to choose a suffix.
+%
+%   addedSuffix:    The suffix added to the end of splitted file.
+%                   DEFAULT: 'ss' is the added suffix.
+%
+%   Example 1:
+%   channelsToRead(4, 'c:\datafolder\datafile.nev', 'tet');
+%
+%   In the example above, the file c:\datafolder\datafile.nev will be used.
+%   The selected NEV file will be saved into a new NEV file that only
+%   contains data from channel 4. The new file will have the added suffix
+%   'tet', so the new filename will be c:\datafolder\datafile-ssXXX.nev.
+%
+%   Example 2:
+%   channelsToRead([5,8,12];
+%
+%   In the example above, the user will be prompted to select a NEV file.
+%   The selected NEV file will be saved into a new NEV file that only
+%   contains data from channels 5, 8, and 12.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.2.2.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: Initial release.
+% 
+% 1.1.0.0:
+%   - Bug fix with saving file names.
+%   - Added ability to pass the file name to the function as an argument.
+%   - Added ability to define the suffix to the split files (addedExtension).
+%
+% 1.2.0.0:
+%   - Fixed a bug related to the # of input arguments and compatibility
+%     with other functions.
+%
+% 1.2.1.0:
+%   - Updated help.
+%
+% 1.2.2.0:
+%   - Fixed a bug where the data was not being saved correctly on Windows
+%     machines.
+%   - Fixed a bug where tetrodes higher than 10 were overwriting tetrodes 1
+%     through 10 over and over again.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Validating the input argument
+if ~exist('channelsToRead', 'var')
+    disp('channelsToRead is a required input argument.');
+    return;
+else
+    channelsToRead = [channelsToRead 65535:-1:65520];
+end
+
+%% Setting the default for addedExtension
+if ~exist('addedSuffix', 'var')
+    addedSuffix = 'ss';
+end
+
+%% Opening the file and reading header
+if ~exist('fileFullPath', 'var')
+    [dataFilename dataFolder] = getFile('*.nev');
+    fileFullPath = [dataFolder dataFilename];
+end
+FID = fopen(fileFullPath, 'r', 'ieee-le');
+
+%% Calculating the header bytes
+BasicHeader = fread(FID, 20, '*uint8');
+headerBytes  = double(typecast(BasicHeader(13:16), 'uint32'));
+dataPacketByteLength = double(typecast(BasicHeader(17:20), 'uint32'));
+
+%% Calculating the data file length and eeking to the beginning of the file
+fseek(FID, 0, 'eof');
+endOfDataByte = ftell(FID);
+dataByteLength = endOfDataByte - headerBytes;
+numberOfPackets = double(dataByteLength) / double(dataPacketByteLength);
+
+%% Reading the header binaries and saving it for future
+fseek(FID, 0, 'bof');
+headerBinaries = fread(FID, headerBytes, '*uint8');
+
+%% Reading the data binaries
+dataBinaries = fread(FID, [dataPacketByteLength numberOfPackets], '*uint8', 0);
+
+%% Finding what PacketIDs have the desired channels
+for IDX = 1:size(dataBinaries,2)
+    PacketIDs(IDX) = typecast(dataBinaries(5:6, IDX), 'uint16');
+end
+packetIDIndices = [];
+for IDX = 1:length(channelsToRead)
+    packetIDsFound = find(PacketIDs == channelsToRead(IDX));
+    packetIDIndices(length(packetIDIndices)+1:length(packetIDIndices)+length(packetIDsFound)) = packetIDsFound;
+end
+packetIDIndices = sort(packetIDIndices);
+
+%% Truncating the data to only contain the desired channels
+newDataBinaries = dataBinaries(:, packetIDIndices);
+
+%% Determining the file name
+currentFileNames = dir([fileFullPath(1:end-4) '-' addedSuffix '*.nev']);
+if ~isempty(currentFileNames)
+    fileIDX = str2num(currentFileNames(end).name(end-6:end-4))+1;
+else
+    fileIDX = 1;
+end
+
+%% Saving the new NEV containig the desired channels
+FIDw = fopen([fileFullPath(1:end-4) '-' addedSuffix sprintf('%03d', fileIDX) fileFullPath(end-3:end)], 'w+', 'n');
+fwrite(FIDw, headerBinaries, 'uint8');
+fwrite(FIDw, newDataBinaries, 'uint8');
+fclose(FID);
+fclose(FIDw);

+ 115 - 0
code/matlab_scripts/NPMK/NEV Utilities/sortNEV.m

@@ -0,0 +1,115 @@
+function [SortedStruct, SortedIndeces] = sortNEV(STRUCT, field, TestValue, Report)
+
+% This function extracts information out of a structure based on the field
+% values. The outputs can be the sorted structure and the indeces of those
+% extracted fields. 
+%
+% Use [SortedStruct, SortedIndeces] = sortNEV(STRUCT, field, TestValue, Report)
+%
+%   STRUCT:     The structure to be used for extraction.
+%
+%   field:      The field in STRUCT that is set as criteria for extraction.
+%               This parameter is optional. If not passed, the function
+%               will prompt the user to provide the name of the field.
+%
+%   TestValue:  The value that "field" needs to be equal to in order to
+%               get extracted.
+%               This parameter is optional. If not passed, the function
+%               will prompt the user to provide the value.
+%
+%   Report:     If this flag is set to 1 the function will show a short
+%               summary of the data that was processed.
+%               This parametere is optional.
+%               DEFAULT: will not show report.
+%
+%   OUTPUT
+%
+%   SortedStruct:   The sorted structure output.
+%   
+%   SortedIndeces:  The indeces to the sorted elements.
+%
+%   Example: 
+%   
+%   [NewStruct, Indeces] = sortNEV(MainStruct, 'TestField', 3, 1);
+%
+%   In the example above, the MainStruct is the structure containing all
+%   elements. The function will search through MainStruct and extract all
+%   elements that have their 'TestField' field set to '3'. It will also
+%   show a report of how many elemenets were processed and how many were
+%   extracted.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   
+%   Version 1.4.1.0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Validates all passed on parameters and will prompt user for any missing
+%  parameter.
+
+if ~exist('field', 'var')
+    field = input('What is the name of the field of interest? ');
+end
+
+while ~isfield(STRUCT, field)
+    display('The field name does not exist. Try again.');
+    field = input('What is the name of the field of interest? ');
+end
+
+if ~exist('TestValue', 'var')
+    TestValue = input('What value does the field need to be equal to (string format)? ');
+end
+
+if ~exist('Report', 'var')
+    Report = 0;
+end
+
+%% Searches through the structure to extract the elements of interest.
+SortedIndeces = NaN(1,length(STRUCT));
+if isa(TestValue, 'double')
+%     display(['Please verify to make sure the field ' field ' does not contain any [] data or the sort will not be successful.'])
+    for strIDX = 1:length(STRUCT)
+        if find(STRUCT(strIDX).(field) == TestValue)
+            SortedIndeces(strIDX) = 1;
+        else
+            SortedIndeces(strIDX) = 0;
+        end
+    end
+    SortedStruct = STRUCT(find(SortedIndeces==1));
+else
+    for strIDX = 1:length(STRUCT)
+        if strcmpi(STRUCT(strIDX).(field), TestValue)
+            SortedIndeces(strIDX) = 1;
+        else
+            SortedIndeces(strIDX) = 0;
+        end
+    end
+    SortedStruct = STRUCT(find(SortedIndeces==1));
+end
+
+
+%% Will define as an empty structure of no instances were found.
+if ~exist('SortedStruct', 'var')
+    display('No instances found.');
+    SortedStruct = struct([]);
+else
+
+%% If the flag is set, it will show a report of how many files were
+%  processed.
+if Report == 1
+    if isempty(SortedStruct)
+        display('No instances found.');
+    else
+        display([num2str(length(SortedStruct)) ' many instances were found and extracted.']);
+    end
+end
+
+%% Will force the function to send an output argument to the caller
+%  environment.
+if (nargout == 0)
+    assignin('caller', 'SortedStruct', SortedStruct);
+end
+
+end

+ 95 - 0
code/matlab_scripts/NPMK/NEV Utilities/splitNEVResets.m

@@ -0,0 +1,95 @@
+function splitNSx(splitCount)
+
+% splitNSx
+% 
+% Opens and splits an NSx file in smaller pieces, timewise.
+%
+% Use splitNSx(splitCount)
+% 
+% All input arguments are optional. Input arguments can be in any order.
+%
+%   splitCount:   Defines the number of splits.
+%                 DEFAULT: Splits the file in 2 pieces.
+%
+%   Example 1: 
+%   splitNSx(4);
+%
+%   In the example above, the user will be prompted to select a file. The
+%   loaded file will be split in 4 samller files. For example, if the file
+%   is 1 hour long then it will be split into four 15-minute files.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 1.1.0.0:
+%   - Fixed a bug related to a case where initial timestamp of the first
+%     data segment was not 0. 
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+
+% Validating input parameter
+if ~exist('splitCount', 'var')
+    splitCount = 2;
+end
+
+% Getting the file name
+[fname, path] = getFile('*.nev', 'Choose an NSx file...');
+if fname == 0
+    disp('No file was selected.');
+    if nargout
+        clear variables;
+    end
+    return;
+end
+fext = fname(end-3:end);
+
+
+
+% Loading the file
+%% Reading Basic Header from file into NSx structure.
+FID                       = fopen([path fname], 'r', 'ieee-le');
+BasicHeader               = fread(FID, 336, '*uint8');
+Trackers.fExtendedHeader  = double(typecast(BasicHeader(13:16), 'uint32'));
+Trackers.countPacketBytes = double(typecast(BasicHeader(17:20), 'uint32'));
+
+%% Doing Trackers
+fseek(FID, 0, 'eof');
+Trackers.fData = ftell(FID);
+Trackers.countDataPacket = (Trackers.fData - Trackers.fExtendedHeader)/Trackers.countPacketBytes;
+
+
+fseek(FID, Trackers.fExtendedHeader, 'bof');
+tRawData  = fread(FID, [10 Trackers.countDataPacket], '10*uint8=>uint8', Trackers.countPacketBytes - 10);
+Timestamp = tRawData(1:4,:);
+Timestamp = typecast(Timestamp(:), 'uint32').';
+
+splitPacketStarts = find(diff(Timestamp)<0);
+splitPacketBytes = Trackers.countPacketBytes * splitPacketStarts;
+
+% Reading headers and seeking to beginning of data
+fseek(FID, 0, 'bof');
+fileHeader = fread(FID, Trackers.fExtendedHeader, '*uint8');
+
+for idx = 1:length(splitPacketStarts)
+    % Opening a file for saving
+    FIDw = fopen([path fname(1:end-4) '-s' sprintf('%03d', idx) fname(end-3:end)], 'w+', 'ieee-le');
+    fprintf('\nReading segment %d... ', idx);
+    % Reading the segment
+    dataSegment = fread(FID, splitPacketBytes(idx), 'char');
+    fprintf('Writing segment %d... ', idx);
+    % Writing the segmented data into file
+    fwrite(FIDw, fileHeader, 'char');
+    fwrite(FIDw, dataSegment, 'char');
+    % Clearing variables and closing file
+    clear dataSegment;
+    fclose(FIDw);
+end

BIN
code/matlab_scripts/NPMK/NPMKverChecker.dat


+ 66 - 0
code/matlab_scripts/NPMK/NPMKverChecker.m

@@ -0,0 +1,66 @@
+function NPMKverChecker()
+
+% NPMKverChecker
+%
+% Checks to see if there is a newer version of NPMK is available for
+% download.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use NPMKverChecker
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: September 13, 2017
+%   - Initial release.
+%
+% 1.0.1.0: September 13, 2017
+%   - Fixed a crash in case there is no Internet connection.
+%
+% 1.0.2.0: January 10, 2018
+%   - Added a clickable URL to the prompt.
+%
+% 1.1.0.0: January 27, 2020
+%   - Only checks for a new version once a week instead of every time.
+%
+
+%% Variables and constants
+gitHubURL = 'https://github.com/BlackrockMicrosystems/NPMK/releases/latest';
+
+%% Find full path of NPMKverChecker.m
+fileFullPath = which('NPMKverChecker.m');
+fileFullPath = [fileFullPath(1:end-1) 'dat'];
+
+%% Check for the latest version fo NPMK
+try
+    if exist(fileFullPath, 'file') == 2
+        load(fileFullPath, '-mat');
+        if floor(abs(now - datenum(checkeddate - days(1)))) > 8 %#ok<NODEF>
+            disp('Checking for a new version of NPMK...');
+            checkver = 1;
+        else
+            checkver = 0;
+        end
+    else
+        checkver = 1;
+    end
+    if checkver
+        FIDv = fopen('Versions.txt');
+        verFile = fscanf(FIDv, '%s'); 
+        fclose(FIDv);
+        latestVersion = verFile(findstr('LATEST', verFile)+7:findstr('LATEST', verFile)+13);
+        gitHubPage = urlread(gitHubURL);
+        newVersionAvailable = findstr(latestVersion, gitHubPage);
+        if isempty(newVersionAvailable)
+            disp('A new version of NPMK may be available.');
+            fprintf('Please visit <a href="%s">GitHub NPMK Page</a> to get the latest version.\n', gitHubURL)
+        end
+        checkeddate = datetime;
+        save(fileFullPath, 'checkeddate');
+    end
+catch
+end

BIN
code/matlab_scripts/NPMK/NSx Utilities/.DS_Store


+ 21 - 0
code/matlab_scripts/NPMK/NSx Utilities/NSxPowerSpectrum.m

@@ -0,0 +1,21 @@
+function NSxPowerSpectrum(NSx, channelNumber, colorCode)
+
+if ~exist('colorCode', 'var')
+    colorCode = 'b';
+end
+
+x = double(NSx.Data(channelNumber,:));
+
+rng default;
+Fs = 300;
+t = linspace(0,1,length(x));
+
+N = length(x);
+xdft = fft(x);
+xdft = xdft(1:N/2+1);
+psdx = (1/(Fs*N)).*abs(xdft).^2;
+psdx(2:end-1) = 2*psdx(2:end-1);
+freq = 0:Fs/length(x):Fs/2;
+plot(freq,10*log10(psdx), colorCode); grid on;
+title('Periodogram Using FFT');
+xlabel('Frequency (Hz)'); ylabel('Power/Frequency (dB/Hz)');

+ 88 - 0
code/matlab_scripts/NPMK/NSx Utilities/NSxToHL.m

@@ -0,0 +1,88 @@
+function NSxToHL(fname)
+
+% NSxToHL
+% 
+% Opens and reads an NSx file without the header information and saves
+% the binary data into a .dat file with the same name. This can be used for
+% specific applications that require this type of data, e.g. Klusters. 
+% Works with File Spec 2.1, 2.2 and 2.3.
+%
+% It does not support pauses at this time.
+%
+% Use OUTPUT = NSxToHL(fname)
+% 
+% All input arguments are optional.
+%
+%   fname:        Name of the file to be opened. If the fname is omitted
+%                 the user will be prompted to select a file. 
+%                 DEFAULT: Will open Open File UI.
+%
+%   OUTPUT:       Contains the binary data.
+%
+%   Example 1: 
+%   NSxToHL('c:\data\sample.ns5');
+%
+%   In the example above, the file c:\data\sample.ns5 will be opened and
+%   the data will be read and saved without the header information in file
+%   sample.ns5.dat.
+%
+%   Example 2:
+%   NSxToHL;
+%
+%   In the example above, the file user will be prompted for the file. The
+%   selected file (e.g. FILENAME.NSx) will be opened and the data will be
+%   read and saved in the file FILENAME.NSx.dat.
+%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.0.0.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Opening the file
+% Popup the Open File UI. Also, process the file name, path, and extension
+% for later use, and validate the entry.
+if ~exist('fname', 'var')
+    if ~ismac
+        [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
+    else
+        [fname, path] = getFile('*.*', 'Choose an NSx file...');
+    end
+    if fname == 0
+        disp('No file was selected.');
+        if nargout
+            clear variables;
+        end
+        return;
+    end
+else
+    if isempty(fileparts(fname))
+        fname = which(fname);
+    end
+    [path,fname, fext] = fileparts(fname);
+    fname = [fname fext];
+    path  = [path '/'];
+end
+if fname==0
+    return; 
+end
+
+%% Reading the headerless file
+data = openNSxHL([path fname]);
+
+%% Writing to file
+% Determining the filename for the converted file
+newFilename = [path fname '.dat'];
+
+% Opening the output file for saving
+FIDw = fopen(newFilename, 'w+', 'ieee-le');
+
+% Writing data into file
+disp('Writing the converted data into the new .dat file...');
+fwrite(FIDw, data, 'int16');

+ 38 - 0
code/matlab_scripts/NPMK/NSx Utilities/calcTimeDelay.m

@@ -0,0 +1,38 @@
+function timeDelay = calcTimeDelay(NSx1, NSx2)
+
+%
+% timeDelay = calcTimeDelay(NSx1, NSx2)
+%
+%   This function calculates the time difference between the end of the
+%   first NSx file and the beginning of the second NSx file.
+%
+%   NSx1:       The first NSx file passed to the function. This input is 
+%               optional. In its absense, a dialog will open and will 
+%               prompt the user to select an NSx file.
+%               (OPTIONAL)
+%
+%   NSx2:       The second NSx file passed to the function. This input is 
+%               also optional. In its absense, a dialog will open and will
+%               prompt the user to select an NSx file.
+%               (OPTIONAL)
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%
+%   Version 1.0.0.0
+
+if ~exist('NSx1', 'var') || ~exist('NSx2', 'var')
+    NSx1 = openNSx;
+    NSx2 = openNSx;
+end
+
+timeDifference = double(NSx2.MetaTags.DateTimeRaw - NSx1.MetaTags.DateTimeRaw);
+timeDifference = timeDifference(end-1)+timeDifference(end)/1000;
+
+timeDelay = (timeDifference*NSx1.MetaTags.SamplingFreq-NSx1.MetaTags.DataPoints)/NSx1.MetaTags.SamplingFreq;
+
+if ~nargout
+    disp(['The time delay between the end of the first file and the beginning of the second file is ' num2str(timeDelay) ' seconds.']);
+    return;
+end

+ 114 - 0
code/matlab_scripts/NPMK/NSx Utilities/combineNSxNEV.m

@@ -0,0 +1,114 @@
+%
+%   [NSx, NEV] = combineNSxNEV(filename1, filename2)
+%
+%   This function loads two NSx and NEV files and it will combine them
+%   together into a sinlge NSx and NEV structure in MATLAB. To merge two
+%   NSx and NEV files into individual files see mergeNSxNEV. The time
+%   difference between the two sets of recordings is removed. To determine
+%   the time differnce between the two data files, use
+%   NSx.MetaTags.DateTimeRaw or NEV.MetaTags.DateTimeRaw variables.
+%
+%
+%   filename1:  The name of the first NSx file. This input is optional. In
+%               its absense, a dialog will open and will prompt the user to
+%               select an NSx file.
+%               (OPTIONAL)
+%
+%   filename2:  The name of the second NSx file. This input is also
+%               optional. In its absense, a dialog will open and will
+%               prompt the user to select an NSx file.
+%               (OPTIONAL)
+%
+%
+%   Example: 
+%   
+%   [NSx, NEV] = combineNSxNEV('c:\data\saveddata1.ns5', 'c:\data\saveddata2.ns5');
+%
+%   The above example reads the two files (full path needed)
+%   c:\data\saveddata1.ns5 and c:\data\saveddata2.ns5 and their corresponding
+%   NEV files (saveddata1.nev and saveddata2.nev) in the same folder and
+%   combines them into single variables NSx and NEV into MATLAB workspace.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%
+%   Version 1.1.2.0
+
+
+function [NSx1, NEV1] = combineNSxNEV(filename1, filename2)
+
+% Openning NSx files
+if exist('filename1', 'var') && exist('filename2', 'var')
+    disp('Load the first NSx file.');
+    NSx1 = openNSx('read', filename1);
+    disp('Load the second NSx file.');
+    NSx2 = openNSx('read', filename2);
+    if NSx1.MetaTags.SamplingFreq ~= NSx2.MetaTags.SamplingFreq;
+        disp('The sampling frequencies are not the same.');
+        return;
+    end
+else
+    NSx1 = openNSx('read');
+    NSx2 = openNSx('read');
+end
+
+% Determining length of the first NSx file
+conversionFactor = 30000/NSx1.MetaTags.SamplingFreq;
+NSx1DataLength = NSx1.MetaTags.DataPoints * conversionFactor;
+
+% Combining NSx files
+NSx1.Data = [NSx1.Data, NSx2.Data];
+
+% Opening NEV files
+fileNameNEV1 = [NSx1.MetaTags.FilePath '/' NSx1.MetaTags.Filename(1:end-3), 'nev'];
+fileNameNEV2 = [NSx1.MetaTags.FilePath '/' NSx2.MetaTags.Filename(1:end-3), 'nev'];
+clear NSx2;
+
+if (exist(fileNameNEV1, 'file') == 2) && (exist(fileNameNEV2, 'file') ==2)
+    disp('Openning corresponding NEV files...');
+    NEV1 = openNEV('read', fileNameNEV1);
+    NEV2 = openNEV('read', fileNameNEV2);
+else
+    disp('Load the first NEV file.');
+    NEV1 = openNEV('read');
+    disp('Load the second NEV file.');    
+    NEV2 = openNEV('read');
+end
+
+% Adjusting the timestamp on the second NEV file
+NEV2.Data.Comments.TimeStamp = NEV2.Data.Comments.TimeStamp + NSx1DataLength;
+NEV2.Data.Comments.TimeStampSec = NEV2.Data.Comments.TimeStampSec + double(NSx1DataLength)/30;
+NEV2.Data.SerialDigitalIO.TimeStamp = NEV2.Data.SerialDigitalIO.TimeStamp + NSx1DataLength;
+NEV2.Data.SerialDigitalIO.TimeStampSec = NEV2.Data.SerialDigitalIO.TimeStampSec + double(NSx1DataLength)/30;
+NEV2.Data.Spikes.TimeStamp = NEV2.Data.Spikes.TimeStamp + NSx1DataLength;
+NEV2.Data.VideoSync.TimeStamp = NEV2.Data.VideoSync.TimeStamp + NSx1DataLength;
+if ~isempty(NEV2.Data.Tracking)
+    trackingFieldNames = fieldnames(NEV2.Data.Tracking);
+    for idx = 1:size(trackingFieldNames, 1)
+        NEV2.Data.Tracking.(trackingFieldNames{idx}).TimeStamp = NEV2.Data.Tracking.(trackingFieldNames{idx}).TimeStamp + NSx1DataLength;
+    end
+end
+NEV2.Data.PatientTrigger.TimeStamp = NEV2.Data.PatientTrigger.TimeStamp + NSx1DataLength;
+NEV2.Data.Reconfig.TimeStamp = NEV2.Data.Reconfig.TimeStamp + NSx1DataLength;
+
+% Combining the two NEV files
+NEV1.Data.Spikes.Electrode      = [NEV1.Data.Spikes.Electrode, NEV2.Data.Spikes.Electrode];
+NEV1.Data.Spikes.TimeStamp      = [NEV1.Data.Spikes.TimeStamp, NEV2.Data.Spikes.TimeStamp];
+NEV1.Data.Spikes.Unit           = [NEV1.Data.Spikes.Unit, NEV2.Data.Spikes.Unit];
+NEV1.Data.Spikes.Waveform       = [NEV1.Data.Spikes.Waveform, NEV2.Data.Spikes.Waveform];
+NEV1.Data.Comments.TimeStamp    = [NEV1.Data.Comments.TimeStamp, NEV2.Data.Comments.TimeStamp];
+NEV1.Data.Comments.TimeStampSec = [NEV1.Data.Comments.TimeStampSec, NEV2.Data.Comments.TimeStampSec];
+NEV1.Data.Comments.CharSet      = [NEV1.Data.Comments.CharSet, NEV2.Data.Comments.CharSet];
+NEV1.Data.Comments.Color        = [NEV1.Data.Comments.Color, NEV2.Data.Comments.Color];
+NEV1.Data.Comments.Text         = [NEV1.Data.Comments.Text; NEV2.Data.Comments.Text];
+if ~isempty(NEV2.Data.Tracking)
+    for idx = 1:size(trackingFieldNames, 1)
+        NEV1.Data.Tracking.(trackingFieldNames{idx}).TimeStamp = [NEV1.Data.Tracking.(trackingFieldNames{idx}).TimeStamp, NEV2.Data.Tracking.(trackingFieldNames{idx}).TimeStamp];
+        NEV1.Data.Tracking.(trackingFieldNames{idx}).TimeStampSec = [NEV1.Data.Tracking.(trackingFieldNames{idx}).TimeStampSec, NEV2.Data.Tracking.(trackingFieldNames{idx}).TimeStampSec];
+        NEV1.Data.Tracking.(trackingFieldNames{idx}).ParentID = [NEV1.Data.Tracking.(trackingFieldNames{idx}).ParentID, NEV2.Data.Tracking.(trackingFieldNames{idx}).ParentID];
+        NEV1.Data.Tracking.(trackingFieldNames{idx}).NodeCount = [NEV1.Data.Tracking.(trackingFieldNames{idx}).NodeCount, NEV2.Data.Tracking.(trackingFieldNames{idx}).NodeCount];
+        NEV1.Data.Tracking.(trackingFieldNames{idx}).MarkerCount = [NEV1.Data.Tracking.(trackingFieldNames{idx}).MarkerCount, NEV2.Data.Tracking.(trackingFieldNames{idx}).MarkerCount];
+        NEV1.Data.Tracking.(trackingFieldNames{idx}).MarkerCoordinates = [NEV1.Data.Tracking.(trackingFieldNames{idx}).MarkerCoordinates NEV2.Data.Tracking.(trackingFieldNames{idx}).MarkerCoordinates];
+    end
+end

+ 168 - 0
code/matlab_scripts/NPMK/NSx Utilities/findSpikes.m

@@ -0,0 +1,168 @@
+function Spikes = findSpikes(NSx, varargin)
+% findSpikes
+%
+% Searches NSx data structure for spikes by thresholding. The output is
+% compatible with NEV.Data.Spikes data structure.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use OUTPUT = findSpikes(NSx, 'threshold', 'preThreshold', 'spikeLength', 'channels', 'duration', 'filter')
+%   
+%    NSx:          The data structure holding the NSx structure
+%
+%    NOTE: All following input arguments are optional. Input arguments may 
+%          be in any order.
+%
+%   'threshold':    The threshold value to apply to the file.
+%                   DEFAULT: -65 uV
+%
+%   'preThreshold': The number of pre-threshold crossing samples to save.
+%                   DEFAULT: 10
+%
+%   'spikeLength':  Length of each extracted spike in number of samples.
+%                   DEFAULT: 48
+%
+%   'channels':     The channels to perform spike extraction on.
+%                   DEFAULT: will perform spike extraction on all channels
+%
+%   'duration':     The duration of file to perform spike extraction on.
+%                   DEFAULT: will perform extraction on the entire file
+%
+%   'filter':       The filter cut-off frequency applied before spike
+%                   extraction.
+%                   DEFAULT: no filter will be applied
+%
+%   OUTPUT:      Contains the NEV.Spikes structure.
+%
+%   USAGE EXAMPLE: 
+%   
+%   Spikes = findSpikes(NSx, 'channels', 1:3, 'duration', 1:10000, 'threshold', -65);
+%   
+%   In the above example the NSx analog data is searched for spikes on
+%   channels 1 through 3 for samples between 1 and 10000. Threshold is
+%   set to -65 uV for all channels.
+%
+%   Spikes = findSpikes(NSx, 'channels', 1:3, 'threshold', [-65 -100 -85]);
+%   In the above example the NSx analog data is searched for spikes among
+%   channels 1 to 3. Thresholds for channel 1 is set to -65 uV, for channel
+%   2 is set to -100 uV, and for channel 3 is set to -85 uV.
+%
+%   Original Author: Ehsan Azar
+%
+%   Contributors: 
+%   Kian Torab, Blackrock Microsystems, ktorab@blackrockmicro.com
+%
+%   Version 1.0.2.0
+%
+
+Spikes = struct('TimeStamp', [],'Electrode', [], 'Unit', [],'Waveform', [], 'findSpikesVer', []);
+
+%% Validating the input arguments. Exit with error message if error occurs.
+spikelen = 48;
+threshold = -65;
+preThreshold = 10;
+filterCorner = 250;
+next = '';
+for i=1:length(varargin)
+    inputArgument = varargin{i};
+    if (strcmpi(next, 'threshold'))
+        next = '';
+        threshold = inputArgument;
+    elseif (strcmpi(next, 'preThreshold'))
+        next = '';
+        preThreshold = inputArgument;
+    elseif (strcmpi(next, 'channels'))
+        next = '';
+        channels = inputArgument;
+    elseif (strcmpi(next, 'duration'))
+        next = '';
+        duration = inputArgument;
+    elseif (strcmpi(next, 'spikeLength'))
+        next = '';
+        spikelen = inputArgument;
+    elseif (strcmpi(next, 'filter'))
+        next = '';
+        filterCorner = inputArgument;
+    elseif strcmpi(inputArgument, 'threshold')
+        next = 'threshold';
+    elseif strcmpi(inputArgument, 'preThreshold')
+        next = 'preThreshold';        
+    elseif strcmpi(inputArgument, 'channels')
+        next = 'channels';        
+    elseif strcmpi(inputArgument, 'duration')
+        next = 'duration';        
+    elseif strcmpi(inputArgument, 'spikeLength')
+        next = 'spikeLength';        
+    elseif strcmpi(inputArgument, 'filter')
+        next = 'filter'; 
+    end
+end
+clear next;
+
+%% Give all input arguments a default value. All input argumens are
+%  optional.
+if ~exist('channels', 'var'); channels = (1:size(NSx.Data, 1))'; end
+if ~exist('duration', 'var'); duration = (1:size(NSx.Data, 2))'; end
+if ~exist('filter', 'var');   filter = [];  end
+
+%% Apply filter
+Data = NSx.Data(channels, duration).';
+
+if ~isempty(filter)
+    [b, a] = butter(4, filterCorner/15000, 'high');
+    Data = filter(b, a, Data);
+end
+
+%% Threshold
+if isfield(NSx, 'ElectrodesInfo');
+    if (isscalar(threshold) && all([NSx.ElectrodesInfo(channels).MaxAnalogValue] == NSx.ElectrodesInfo(1).MaxAnalogValue) && ...
+            all([NSx.ElectrodesInfo(channels).MaxDigiValue] == NSx.ElectrodesInfo(1).MaxDigiValue))
+        threshold = (threshold * double(NSx.ElectrodesInfo(1).MaxDigiValue) / ...
+            double(NSx.ElectrodesInfo(1).MaxAnalogValue)); % scalar threshold
+    else
+        threshold = (threshold .* double([NSx.ElectrodesInfo(channels).MaxDigiValue]) ./ ...
+            double([NSx.ElectrodesInfo(channels).MaxAnalogValue])); % vector threshold
+    end
+    threshold = cast(threshold, class(Data));
+end
+
+[row, col] = find((diff(bsxfun(@minus, Data, threshold) > 0) < 0).');
+clear threshold;
+Spikes.TimeStamp = col' - preThreshold;
+clear col;
+Spikes.Electrode = row';
+clear row;
+
+Spikes.Electrode(Spikes.TimeStamp < 1) = [];
+Spikes.TimeStamp(Spikes.TimeStamp < 1) = [];
+Spikes.Electrode(Spikes.TimeStamp + spikelen > size(NSx.Data, 2)) = [];
+Spikes.TimeStamp(Spikes.TimeStamp + spikelen > size(NSx.Data, 2)) = [];
+
+%% Lockout violation removal
+% this makes sure all spikes are at least one spike length apart
+ii = 1;
+while (ii < length(Spikes.TimeStamp))
+    idx = find((Spikes.Electrode((ii+1):end) == Spikes.Electrode(ii)) & ...
+        (Spikes.TimeStamp((ii+1):end) - Spikes.TimeStamp(ii) >= spikelen), 1);
+    if (isempty(idx))
+        idx = find(Spikes.Electrode((ii+1):end) == Spikes.Electrode(ii));
+    else
+        idx = find(Spikes.Electrode((ii+1):(ii+idx-1)) == Spikes.Electrode(ii));
+    end
+    if (~isempty(idx))
+        Spikes.Electrode(ii + idx) = [];
+        Spikes.TimeStamp(ii + idx) = [];
+    end
+    ii = ii + 1;
+end
+clear idx;
+
+%% Spike extraction
+Spikes.Waveform = zeros(spikelen, length(Spikes.TimeStamp));
+for ii = 1:length(Spikes.TimeStamp)
+    ts = Spikes.TimeStamp(ii):(Spikes.TimeStamp(ii) + spikelen - 1);
+    Spikes.Waveform(:, ii) = Data(ts, Spikes.Electrode(ii));
+end
+% convert index to actual channel number
+Spikes.Electrode = channels(Spikes.Electrode);
+
+

+ 148 - 0
code/matlab_scripts/NPMK/NSx Utilities/matrixToNSx.m

@@ -0,0 +1,148 @@
+function matrixToNSx(varargin)
+
+% matrixToNSx
+% 
+% Converts a MATLAB data matrix (channels as rows, samples as columns) into
+% a NSx file.
+%
+% Use matrixToNSx(inputData, samplingFreq, inputUnits, savedDataPath)
+% 
+% All input arguments are optional.
+%
+%   inputData:     data matrix (channels as rows, samples as columns) into
+%                  a NSx file.
+%
+%   samplingFreq:  Sampling frequency of the data. Currently only 500Hz,
+%                  1kHz, 2kHz, 10kHz, and 30kHz sampaling frequencies are
+%                  supported.
+%
+%   inputUnits:    The unit for the recorded data. Most data acquisition 
+%                  systems save the data in units of µV. TDT units are V.
+%                  The supported units are V, mV, uV or nV.
+%
+%   savedDataPath: The full path (excluding the extension) of the saved
+%                  file.
+%
+%   Example 1 (Mac): 
+%   matrixToNSx(myData, 30000, 'uv', '/Desktop/newConvertedFile');
+%
+%   In the example above, the data matrix myData recorded at 30kHz will be
+%   saved on the Desktop (Mac style path) as newConvertedFile.ns5 file.
+%
+%   Example 2 (PC): 
+%   matrixToNSx(myData, 30000, 'uv', 'C:\Data\newConvertedFile');
+%
+%   In the example above, the data matrix myData recorded at 30kHz will be
+%   saved C:\Data folder as newConvertedFile.ns5 file.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+switch nargin
+    case 0
+        disp('Data is a required input.');
+        return
+    case 1
+        disp('Sampling rate and input unit were not provided. Assuming 30kHz and µV.');
+        disp('The converted file will be saved on the Desktop.');
+        inputData = varargin{1};
+        samplingFreq = input('What is the sampling frequency of the recorded data (e.g. ''30000'')? ');
+        signalUnit = input('What is the input unit of the signal (V, mV, uV or nV)? ', 's');
+        savedFilePath = input('Enter the full path for the converted file? ', 's');
+    case 2
+        disp('Input unit was not provided. Assuming µV.');
+        disp('The converted file will be saved on the Desktop.');
+        inputData = varargin{1};
+        signalUnit = input('What is the input unit of the signal (V, mV, uV or nV)? ', 's');
+        savedFilePath = input('Enter the full path for the converted file? ', 's');
+    case 3
+        disp('The converted file will be saved on the Desktop.');
+        inputData = varargin{1};
+        samplingFreq = varargin{2};
+        signalUnit = varargin{3};
+        savedFilePath = input('Enter the full path for the converted file? ', 's');
+    case 4
+        inputData = varargin{1};
+        samplingFreq = varargin{2};
+        signalUnit = varargin{3};
+        savedFilePath = varargin{4};
+    otherwise
+        disp('Invalid number of arguments.');
+        return;
+end
+
+%% Validate sampling frequency
+switch samplingFreq
+    case 500
+        savedFileExt = '.ns1';
+    case 1000
+        savedFileExt = '.ns2';
+    case 2000
+        savedFileExt = '.ns3';
+    case 10000
+        savedFileExt = '.ns4';
+    case 30000
+        savedFileExt = '.ns5';
+    otherwise
+        disp('Currently only sampling rates 500Hz, 1kHz, 2kHz, 10 kHz and 30kHz are supported.');
+        return;
+end
+
+%% Finding the unit of the data.
+switch lower(signalUnit)
+    case 'v'
+        inputData = inputData * 1000000;
+    case 'mv'
+        inputData = inputData * 1000;
+    case 'uv'
+        
+    case 'nv'
+        inputData = inputData / 1000;
+    otherwise
+        disp('Invalid unit.');
+        return;
+end
+
+%% Converting samplingFreq to type double
+samplingFreq = double(samplingFreq);
+
+% Warren from More lab @ Stanford
+%% Determining channel count and data length
+channelCount = min(size(inputData));
+dataLength = max(size(inputData));
+
+%% Creating a label of 16 character long.
+newChanLabel = [num2str(samplingFreq/1000) ' kS/s'];
+newChanLabel = [newChanLabel repmat(' ', [1, 16-length(newChanLabel)])];
+
+%% Converting inputData to int16
+inputData = int16(inputData);
+
+%% Rewriting the metatags
+NSx = openNSx(which('bnsx.dat'));
+NSx.MetaTags.SamplingLabel = newChanLabel(1:16);
+NSx.MetaTags.ChannelCount = channelCount;
+NSx.MetaTags.SamplingFreq = samplingFreq;
+NSx.MetaTags.TimeRes = samplingFreq;
+NSx.MetaTags.ChannelID = 1:NSx.MetaTags.ChannelCount;
+NSx.MetaTags.DateTime = datestr(now);
+d = datevec(date);
+NSx.MetaTags.DateTimeRaw = [d(1:2), weekday(date), d(3:end), 0];
+NSx.MetaTags.Comment = ['This data was converted into a NSx by matrixToNSx' repmat(' ',1, 207)];
+NSx.MetaTags.FileSpec = '2.3';
+NSx.MetaTags.Timestamp = 0;
+NSx.MetaTags.DataPoints = dataLength;
+NSx.MetaTags.DataDurationSec = NSx.MetaTags.DataPoints / NSx.MetaTags.SamplingFreq;
+NSx.Data = inputData;
+
+saveNSx(NSx, [savedFilePath savedFileExt]);

+ 233 - 0
code/matlab_scripts/NPMK/NSx Utilities/mergeNSxNEV.m

@@ -0,0 +1,233 @@
+%
+%   mergeNSxNEV(filename1, filename2)
+%
+%   This function loads two NSx and NEV files and it will combine them
+%   together into one file. The resulting file will be saved as new NSx
+%   and NEV files onto the disk.  To combine two NSx and NEV files into 
+%   indivual NSx and NEV variables in MATLAB see combineNSxNEV. The time
+%   difference between the two sets of recordings is removed. To determine
+%   the time differnce between the two data files, use
+%   NSx.MetaTags.DateTimeRaw or NEV.MetaTags.DateTimeRaw variables.
+%
+%
+%   filename1:  The name of the first NSx file. This input is optional. In
+%               its absense, a dialog will open and will prompt the user to
+%               select an NSx file.
+%               (OPTIONAL)
+%
+%   filename2:  The name of the second NSx file. This input is also
+%               optional. In its absense, a dialog will open and will
+%               prompt the user to select an NSx file.
+%               (OPTIONAL)
+%
+%   Example: 
+%   
+%   mergeNSxNEV('c:\data\saveddata1.ns5', 'c:\data\saveddata2.ns5');
+%
+%   The above example reads the two files (full path needed)
+%   c:\data\saveddata1.ns5 and c:\data\saveddata2.ns5 and their corresponding
+%   NEV files (saveddata1.nev and saveddata2.nev) in the same folder and
+%   merges them into a single file called firstrecording001-combined.ns2
+%   and firstrecording001-combined.nev.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%
+%   Version 1.2.2.0
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: Initial release
+%
+% 1.2.2.0: August 3, 2016
+%   - Fixed a bug that resulted in a crash if one of two NEV files weren't
+%     available.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+function mergeNSxNEV(varargin)
+
+if nargin == 3
+    if strcmpi(varargin{1}, 'nowarning')
+        warningMessage = varargin{1};
+        filename1 = varargin{2};
+        filename2 = varargin{3};
+    elseif strcmpi(varargin{3}, 'nowarning')
+        filename1 = varargin{1};
+        filename2 = varargin{2};
+        warningMessage = varargin{3};
+    else
+        disp('Invalid arguments. See help by typing ''help mergeNSxNEV''');
+        return;
+    end
+elseif nargin == 2
+    filename1 = varargin{1};
+    filename2 = varargin{2};
+    warningMessage = 'warning';
+elseif nargin == 1
+    warningMessage = varargin{1};
+elseif nargin == 0
+    warningMessage = 'warning';
+else
+    disp('Invalid number of arguments. See help by typing ''help mergeNSxNEV''');
+    return;
+end
+
+%% Warning
+if ~strcmpi(warningMessage, 'nowarning')
+    fprintf(2, '\nCaution! This scripts assumes that the two segments of NSx ');
+    fprintf(2, '\nand NEV files are from the same recording session. The settings ');
+    fprintf(2, '\nmust be identical. Always verify the merge to assure it was done');
+    fprintf(2, '\ncorrectly. To suppress this message, run mergeNSxNEV with command');
+    fprintf(2, '\n''nowarning''. Ex: mergeNSxNEV(''nowarning'').\n\n');
+end
+
+%% Getting the file names
+if exist('filename1', 'var') && exist('filename2', 'var')
+    if exist(filename1, 'file') && exist(filename2, 'file')
+        NSx1FullName = filename1;
+        NEV1FullName = [NSx1FullName(1:end-3) 'nev'];
+        NSx2FullName = filename2;
+        NEV2FullName = [NSx2FullName(1:end-3) 'nev'];
+    else
+        disp('One or both files do not exist.');
+        return;
+    end
+else
+    disp('Load the first NSx file.');
+    if ~ismac
+        [NSx1dataFilename, NSx1dataFolder] = getFile('*.ns*', 'Choose the first NSx file...');
+    else
+        [NSx1dataFilename, NSx1dataFolder] = getFile('*.*', 'Choose the first NSx file...');
+    end
+    if NSx1dataFilename == 0
+        disp('No file was selected.');
+        return;
+    end
+    disp('Load the second NSx file.');
+    if ~ismac
+        [NSx2dataFilename, NSx2dataFolder] = getFile('*.ns*', 'Choose the second NSx file...');
+    else
+        [NSx2dataFilename, NSx2dataFolder] = getFile('*.*', 'Choose the second NSx file...');
+    end
+    if NSx2dataFilename == 0
+        disp('No file was selected.');
+        return;
+    end
+    NSx1FullName = strcat(NSx1dataFolder, NSx1dataFilename);
+    NSx2FullName = strcat(NSx2dataFolder, NSx2dataFilename);
+	NEV1FullName = [NSx1FullName(1:end-3) 'nev'];
+	NEV2FullName = [NSx2FullName(1:end-3) 'nev'];
+end
+
+%% Reading NSx1
+NSx1 = openNSx(NSx1FullName);
+FID1 = fopen(NSx1FullName, 'r', 'ieee-le');
+fread(FID1, 10, '*int8');
+NSx1HeaderBytes = typecast(NSx1.RawData.Headers(11:14), 'uint32');
+fread(FID1, NSx1HeaderBytes+5, '*int8');
+NSx1DataLength = NSx1.MetaTags.DataPoints;
+fseek(FID1, 0, 'bof');
+NSx1Data = fread(FID1, '*int8');
+fclose(FID1);
+
+NSx1LengthIn30k = NSx1DataLength * (NSx1.MetaTags.TimeRes / NSx1.MetaTags.SamplingFreq);
+
+
+%% Reading NSx2
+FID2 = fopen(NSx2FullName, 'r', 'ieee-le');
+fread(FID2, 10, '*int8');
+NSx2HeaderBytes = fread(FID2, 1, '*int32');
+fseek(FID2, 0, 'bof');
+fread(FID2, NSx2HeaderBytes+5, '*int8');
+NSx2DataLength = fread(FID2, 1, '*uint32');
+NSx2Data = fread(FID2, '*int8');
+fclose(FID2);
+
+%% Combining the two files and adjusting data length
+NSx1Data(NSx1HeaderBytes + 5 + 1:NSx1HeaderBytes + 9) = typecast((NSx1DataLength + NSx2DataLength), 'int8');
+NSx1Data = [NSx1Data; NSx2Data];
+
+
+%% Writing data back to combined file
+
+% Writing header into the file
+newFilename = [NSx1FullName(1:end-4) '-combined.' NSx1FullName(end-2:end)];
+if exist(newFilename, 'file') == 2
+    overwriteFlag = input('The NSx file already exists. Overwrite? ', 's');
+    if ~strcmpi(overwriteFlag, 'y')
+        clear all;
+        return;
+    end
+end
+
+% Writing combined NSx
+FIDw = fopen(newFilename, 'w+', 'ieee-le');
+disp('Writing NSx data back into the combined file...');
+fwrite(FIDw, NSx1Data, 'int8');
+fclose(FIDw);
+
+%% Opening the NEV files
+
+if ~exist('NEV1FullName', 'var')
+    disp('Load the first NEV file.');
+    [NEV1dataFilename NEV1dataFolder] = getFile('*.*');
+    disp('Load the second NEV file.');
+    [NEV2dataFilename NEV2dataFolder] = getFile('*.*');
+
+    NEV1FullName = strcat(NEV1dataFolder, NEV1dataFilename);
+    NEV2FullName = strcat(NEV2dataFolder, NEV2dataFilename);
+end
+
+%% Reading NEV1
+FID1 = fopen(NEV1FullName, 'r', 'ieee-le');
+FID2 = fopen(NEV2FullName, 'r', 'ieee-le');
+okNEV = (FID1 ~= -1) && (FID2 ~= -1);
+if okNEV
+    NEV1Data = fread(FID1, '*int8');
+    fclose(FID1);
+
+    %% Reading NEV2
+    fseek(FID2, 12, 'bof');
+    NEV2HeaderBytes = fread(FID2, 1, '*int32');
+    NEV2BytesinDataPackets = fread(FID2, 1, '*int32');
+    fseek(FID2, NEV2HeaderBytes, 'bof');
+    NEV2Data = fread(FID2, '*int8');
+    fclose(FID2);
+
+    %% Adding the timestamp of the first file to the second file
+    NEV2Data = typecast(NEV2Data, 'uint32');
+    NEV2Data = reshape(NEV2Data, NEV2BytesinDataPackets/4, length(NEV2Data)/(NEV2BytesinDataPackets/4));
+    NEV2Data(1,:) = NEV2Data(1,:) + NSx1LengthIn30k;
+    NEV2Data = reshape(NEV2Data, size(NEV2Data, 1) * size(NEV2Data, 2), 1);
+    NEV2Data = typecast(NEV2Data, 'int8');
+
+    NEV3Data = [NEV1Data; NEV2Data];
+
+    %% Writing data back to combined NEV file
+
+    % Writing header into the file
+    newFilename = [NEV1FullName(1:end-4) '-combined.' NEV1FullName(end-2:end)];
+    if exist(newFilename, 'file') == 2
+        overwriteFlag = input('The NEV file already exists. Overwrite? ', 's');
+        if ~strcmpi(overwriteFlag, 'y')
+            clear all;
+            return;
+        end
+    end
+
+    % Writing combined NEV
+    FIDCombined = fopen(newFilename, 'w+', 'ieee-le');
+    disp('Writing NEV data back into the combined file...');
+    fwrite(FIDCombined, NEV3Data, 'int8');
+    fclose(FIDCombined);
+    clear all;
+else
+    disp('One or more NEV files were not found. Skipping NEV merging.');
+end

+ 60 - 0
code/matlab_scripts/NPMK/NSx Utilities/mergeNSxNEVSeries.m

@@ -0,0 +1,60 @@
+%
+%   mergeNSxNEV()
+%
+%   This function loads two NSx and NEV files and it will combine them
+%   together into one file. The resulting file will be saved as new NSx
+%   and NEV files onto the disk.  To combine two NSx and NEV files into 
+%   indivual NSx and NEV variables in MATLAB see combineNSxNEV. The time
+%   difference between the two sets of recordings is removed. To determine
+%   the time differnce between the two data files, use
+%   NSx.MetaTags.DateTimeRaw or NEV.MetaTags.DateTimeRaw variables.
+%
+%
+%   filename1:  The name of the first NSx file. This input is optional. In
+%               its absense, a dialog will open and will prompt the user to
+%               select an NSx file.
+%               (OPTIONAL)
+%
+%   filename2:  The name of the second NSx file. This input is also
+%               optional. In its absense, a dialog will open and will
+%               prompt the user to select an NSx file.
+%               (OPTIONAL)
+%
+%   Example: 
+%   
+%   mergeNSxNEV('c:\data\saveddata1.ns5', 'c:\data\saveddata2.ns5');
+%
+%   The above example reads the two files (full path needed)
+%   c:\data\saveddata1.ns5 and c:\data\saveddata2.ns5 and their corresponding
+%   NEV files (saveddata1.nev and saveddata2.nev) in the same folder and
+%   merges them into a single file called firstrecording001-combined.ns2
+%   and firstrecording001-combined.nev.
+%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.0.0.0
+%   March 31, 2014
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+function mergeNSxNEV(varargin)
+
+if nargin >= 1
+    disp('Too many input arguments.');
+    return;
+end
+
+%% Opening the file
+% Getting the name of the first file from the user
+[gfFileName gfPathName] = getFile;
+[filePath, fileName, fileExt] = fileparts(gfFileName);
+
+

+ 118 - 0
code/matlab_scripts/NPMK/NSx Utilities/openNSxHL.m

@@ -0,0 +1,118 @@
+function OUTPUT = openNSxHL(fname)
+
+% openNSxHL
+% 
+% Opens and reads an NSx file without the header information and returns
+% the binary data. This can be used for specific applications that require
+% this type of data, e.g. Klusters. Works with File Spec 2.1, 2.2 and 2.3.
+% It does not support pauses at this time.
+%
+%
+% Use OUTPUT = openNSx(fname)
+% 
+% All input arguments are optional.
+%
+%   fname:        Name of the file to be opened. If the fname is omitted
+%                 the user will be prompted to select a file. 
+%                 DEFAULT: Will open Open File UI.
+%
+%   OUTPUT:       Contains the binary data.
+%
+%   Example 1: 
+%   openNSxHL('c:\data\sample.ns5');
+%
+%   In the example above, the file c:\data\sample.ns5 will be opened and
+%   the data will be read and output through variable OUTPUT.
+%
+%   Example 2:
+%   openNSxHL;
+%
+%   In the example above, the file user will be prompted for the file. The
+%   selected file will be opened and the data will be read and output
+%   through variable OUTPUT.
+%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.0.0.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 1.1.0.0: June 16, 2017
+%   - Pads the data with zeros when the beginning timestamp is not 0.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Opening the file
+% Popup the Open File UI. Also, process the file name, path, and extension
+% for later use, and validate the entry.
+if ~exist('fname', 'var')
+    if ~ismac
+        [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
+    else
+        [fname, path] = getFile('*.*', 'Choose an NSx file...');
+    end
+    if fname == 0
+        disp('No file was selected.');
+        if nargout
+            clear variables;
+        end
+        return;
+    end
+else
+    if isempty(fileparts(fname))
+        fname = which(fname);
+    end
+    [path,fname, fext] = fileparts(fname);
+    fname = [fname fext];
+    path  = [path '/'];
+end
+if fname==0
+    return; 
+end
+
+%% Reading the file data
+% Opening the file
+FID          = fopen([path fname], 'r', 'ieee-le');
+FileTypeID   = fread(FID, [1,8]   , '*char');
+% Finding the begining of the data point in the file
+if strcmpi(FileTypeID, 'NEURALSG')
+    fseek(FID, 20, 'cof');
+    ChannelCount  = double(fread(FID, 1, 'uint32=>double'));
+    fread(FID, [ChannelCount 1], '*uint32');
+    HeaderBytes   = ftell(FID);
+elseif strcmpi(FileTypeID, 'NEURALCD')
+    dataHeaderBytes = 9;
+    BasicHeader   = fread(FID, 306, '*uint8');
+    HeaderBytes   = double(typecast(BasicHeader(3:6), 'uint32'));
+else
+    disp('This version of NSxToXXX can only read File Specs 2.1, 2.2 and 2.3');
+    disp(['The selected file spec is ' NSx.MetaTags.FileSpec '.']);
+    fclose(FID);
+    clear variables;
+    return;
+end
+
+% Finding the number of channels
+fseek(FID, 310, 'bof');
+numofChannels = fread(FID, 1, '*uint32');
+
+% Skipping to the point where the data is saved, skipping the header info
+fseek(FID, HeaderBytes, 'bof');
+
+% Finding the beginning timestamp so it can be padded with zeros in case
+% it's not 0 already.
+fseek(FID, 1, 'cof'); % Skipping to timestamp
+begTimestamp = fread(FID, 1, '*uint32');
+paddedZeros = zeros(numofChannels * begTimestamp * 2, 1);
+fseek(FID, 4, 'cof'); % Skipping to data
+
+% Reading the header-less data
+disp(['Reading the data from file ' path fname '...']);
+OUTPUT = fread(FID, inf, '*int16');
+OUTPUT = [paddedZeros; OUTPUT];
+fclose(FID);

+ 115 - 0
code/matlab_scripts/NPMK/NSx Utilities/plotAverageWaveforms.m

@@ -0,0 +1,115 @@
+% plotAverageWaveforms
+%
+% Plots average waveforms for all channels and specified units across the
+% array. It will prompt for a CMP file to map each channel to its electrode
+% representation.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
+% Use plotAverageWaveforms(NEV, units)
+% 
+% NOTE: All input arguments are optional. Input arguments may be in any order.
+%
+%   NEV:          NEV structure containing all waveforms.
+%                 DEFAULT: Will prompt for NEV.
+%
+%   'units':      Specify the units to plot (i.e. 2 or 0:5 for all).
+%                 DEFAULT: will plot all units.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   USAGE EXAMPLE: 
+%   
+%   openNEV(NEV, 0:3);
+%
+%   In the example above, the waveforms in the NEV structure coming from
+%   units 0 through 3 will be plotted.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%   Salt Lake City, UT
+%   
+%   Version 2.1.0.0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 2.1.0.0:
+%   - Added the ability to plot scaled or non-scaled plots. By default, the
+%   plots are scaled.
+%   - The color of the first unit is always selected at random, so when a
+%   channel only has 1 unit, that 1 unit will be a different color
+%   (visualization only).
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function plotAverageWaveforms(NEV, units, plottype)
+
+mapfile = 1;
+colors = repmat({'magenta', 'cyan', 'red', 'green', 'blue', 'black'}, 1, 3);
+
+if ~exist('NEV', 'var')
+    NEV = openNEV('read');
+end
+
+if ~exist('units', 'var')
+    units = 0:5;
+end
+
+if ~exist('plottype', 'var')
+    plottype = 'scaled';
+end
+
+numberOfElectrodes = length(unique(NEV.Data.Spikes.Electrode));
+
+disp('Select a map file for your array. If none, press cancel or ESC.');
+mapFile = KTUEAMapFile;
+if ~mapFile.isValid
+    disp('Map File was not selected.');
+    mapfile = 0;
+    plotHeight = floor(sqrt(numberOfElectrodes));
+    plotWidth = ceil(numberOfElectrodes/floor(sqrt(numberOfElectrodes)));
+end
+
+figure = KTFigure;
+
+figure.EnlargeFigure;
+figure.MakeBackgroundWhite;
+figure.SetActive;
+title('Spikes Average Waveforms for Individual Channels');
+
+for chanIDX = 1:numberOfElectrodes
+    
+    if mapfile
+try
+        mapFile.GenerateChannelSubplot(chanIDX);
+catch
+    disp('e');
+end
+    else
+        subplot(plotHeight, plotWidth, chanIDX);
+    end
+    
+    hold on;
+    initialColor = round(rand(1)*5);
+    for unitIDX = units
+        [~, allWaveforms] = findEventTimes(NEV, chanIDX, unitIDX);
+        if ~isempty(allWaveforms)
+            averageWaveform = mean(allWaveforms, 2);
+            plot(averageWaveform, 'color', colors{unitIDX+1+initialColor}, 'LineWidth',2);
+        end
+    end
+    hold off;
+    
+    if strcmpi(plottype, 'scaled')
+        ylim([-1000, 1000]);
+    end
+%     if size(allWaveforms,2) ~= 0
+%         text(1, 0, num2str(size(allWaveforms,2)), 'color', 'red');
+%     end
+    mapFile.setAxisBackgroundColor('white');
+    set(gca, 'XTick', []);
+    set(gca, 'YTick', []);
+end

+ 93 - 0
code/matlab_scripts/NPMK/NSx Utilities/removeNSxData.m

@@ -0,0 +1,93 @@
+function removeNSxData(timestamps, filename)
+%
+%   removeNSxData(timestamps, filename)
+%
+%   This function removes chunks of data given in a 2-column timestamps
+%   variable from a NSx file and then saves it as another NSx. This is
+%   useful when removing useless data from the file to decrease the size of
+%   the NSx file without modifying the file timestamps. The file size only
+%   changes when the NSx file is compressed.
+%
+%   timestamps: This variable contains beginning and ending timestamps of
+%               the data that need to be removed from the NSx file. The
+%               format is:
+%                          [BegTimeStamp1 EndTimeStamp1
+%                           BegTimeStamp2 EndTimeStamp2
+%                           BegTimeStamp3 EndTimeStamp3
+%                                ...          ...
+%                           BegTimeStampN EndTimeStampN]
+%
+%               The data in the NSx between the pairs of timestamps will be
+%               removed and set to 0.
+%               (REQUIRED)
+%
+%   filename:   The name of the NSx file to be used. This input is also
+%               optional. In its absense, a dialog will open and will
+%               prompt the user to select an NSx file.
+%               (OPTIONAL)
+%
+%   Example:    removeNSxData([100,600; 1000,2000], 'c:\datafile\sampleNSx.ns5')
+%
+%               In the example above, the timestamps between 100:600 and
+%               1000:2000 will be removed from the file sampleNSx.ns5 and
+%               the resulting NSx will be saved in sampleNSx_chunked.ns5
+%               file.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%
+%   Version 1.0.1.0
+
+% Validating the timestamps variable
+if ~exist('timestamps', 'var')
+    disp('The variable timestamps is required.');
+    return;
+end
+
+if size(timestamps, 2) ~= 2
+    disp('The timestamps variable should be a Nx2 variable containing beginning timestamps in the first column and ending timestamps in the second column.');
+    return;
+end
+
+if ~all(timestamps(:,1) < timestamps(:,2))
+    disp('The timestamps in the first column (beginning) have to be smaller than the ones in the second column (ending).')
+    return;
+end
+    
+% Figuring out the filename, if not passed on to the function
+if ~exist('filename', 'var')
+	[fname, path] = getFile('*.*', 'Choose an NSx file...');
+    filename = [path fname];
+end
+
+if exist(filename, 'file') ~= 2
+    disp('The file does not exist.');
+    return;
+end
+
+% Openning and reading the file
+FID = fopen(filename, 'r', 'ieee-le');
+readData = fread(FID, '*uint8');
+FID = fclose(FID);
+
+% Extracting some information from the NSx file
+fileTypeID   = char(readData(1:8))';
+headerBytes  = typecast(readData(11:14), 'uint32')+9;
+samplingFreq = double(typecast(readData(291:294), 'uint32'))/...
+               double(typecast(readData(287:290), 'uint32'));
+channelCount = typecast(readData(311:314), 'uint32');
+
+% Converting timestamps into uint16 (2 bytes per data point)
+timestamps = timestamps*2;
+
+% Removing given timestamps
+for idx = 1:size(timestamps, 1)
+    readData((timestamps(idx,1)-2)*channelCount+1+headerBytes:timestamps(idx,2)*channelCount+headerBytes) = NaN;
+end
+
+% Saving the chunked file
+writeFilename = [filename(1:end-4) '_chunked', filename(end-3:end)];
+FID = fopen(writeFilename, 'w+', 'ieee-le');
+fwrite(FID, readData);
+fclose(FID);    

+ 150 - 0
code/matlab_scripts/NPMK/NSx Utilities/rethresholdNSx.m

@@ -0,0 +1,150 @@
+function NEV = rethresholdNSx(varargin)
+
+% rethresholdNSx
+% 
+% Opens a NEV file and rethresholds it. It outputs a NEV structure into
+% MATLAB. This version currently does not save a new NEV file.
+% 
+% All input arguments are optional. Input arguments must be in the
+% following order:
+%
+%   NSx:          The data structure holding the channel information
+%
+%   Threshold:    The threshold value in µV. This can be a positive or
+%                 negative value.
+%                 DEFAULT: Will automatically set threshold to -65 µV.
+%
+%   FilterFreq:   The high-pass filter high-pass corner frequency. For
+%                 example, if the filter is set to 250 then the signal will
+%                 first get high-pass filtered at 250 Hz before getting
+%                 rethrholded.
+%                 DEFAULT: Will automatically high-pass filter signal at
+%                 250 Hz.
+%
+%   Example: 
+%   
+%   NEV = rethresholdNSx(NSx, -85, 150);
+%
+%   In the example above, the NSx structure will be high-pass filtered at 
+%   150 Hz and then rethresholded at -85 µV. All new waveformes will be
+%   saved in a NEV structure and will get output to MATLAB.
+%
+%   NEV = rethresholdNSx;
+%
+%   In the example above, the user will be propted to choose a NSx file
+%   then the signal will get high-pass filtered at 150 Hz and then 
+%   rethresholded at -85 µV. All new waveformes will be saved in a NEV 
+%   structure and will get output to MATLAB.
+%
+%   Kian Torab
+%   Blackrock Microsystems
+%   kian@blackrockmicro.com
+%
+%   Version 1.0.0.0
+%
+
+if nargin > 3
+    disp('Invalid number of arguments. See ''help rethresholdNSx'' for more information.');
+elseif nargin == 3
+    NSx = varargin{1};
+    try
+        NEV = openNEV([NSx.MetaTags.FilePath '/' NSx.MetaTags.Filename(1:end-3) 'nev'], 'read');
+    catch
+        disp('Cannot open the corresponding NEV file.');
+        disp('The NEV file is required. Please place it in the same folder.');
+        return;
+    end
+    threshold = varargin{2};
+    hpFreq = varargin{3};
+elseif nargin == 2
+    NSx = varargin{1};
+    try
+        NEV = openNEV([NSx.MetaTags.FilePath '/' NSx.MetaTags.Filename(1:end-3) 'nev'], 'read');
+    catch
+        disp('Cannot open the corresponding NEV file.');
+        disp('The NEV file is required. Please place it in the same folder.');
+        return;
+    end
+    threshold = varargin{2};
+    hpFreq = 250;
+elseif nargin == 1
+    NSx = varargin{1};
+    try
+        NEV = openNEV([NSx.MetaTags.FilePath '/' NSx.MetaTags.Filename(1:end-3) 'nev'], 'read');
+    catch
+        disp('Cannot open the corresponding NEV file.');
+        disp('The NEV file is required. Please place it in the same folder.');
+        return;
+    end
+    threshold = -85;
+    hpFreq = 250;
+elseif nargin == 0
+    [fileName pathName] = getFile;
+    NSx = openNSx([pathName fileName], 'read');
+    try
+        NEV = openNEV([pathName fileName(1:end-3) 'nev'], 'read');
+    catch
+        disp('Cannot open the corresponding NEV file.');
+        disp('The NEV file is required. Please place it in the same folder.');
+        return;
+    end
+    threshold = -50;
+    hpFreq = 250;
+end
+
+%% Setting stuff up
+newSpikes.TimeStamps = 0;
+newSpikes.Electrode = 0;
+newSpikes.Unit = 0;
+newSpikes.Waveform = zeros(48,1);
+firstTimeFlag = 1;
+
+digitizationFactor = 1000/NEV.ElectrodesInfo(1).DigitalFactor;
+wavelengthLength = length(NEV.Data.Spikes.Waveform(:,1));
+availableChannels = double(NSx.MetaTags.ChannelID)';
+
+%% Highpass filter continuous data
+
+
+
+%% Finding the spikes
+
+for channelIDX = 1:length(availableChannels)
+    if threshold < 0
+        thresholdTimestamps = find(diff(NSx.Data(channelIDX,:) < threshold*digitizationFactor) == 1);
+    else
+        thresholdTimestamps = find(diff(NSx.Data(channelIDX,:) > threshold*digitizationFactor) == 1);
+    end
+    idx = 1;
+    while idx < length(thresholdTimestamps)
+        refractoryIDX = find(abs(thresholdTimestamps(idx) - thresholdTimestamps) < wavelengthLength);
+        thresholdTimestamps(refractoryIDX(2:end)) = [];
+        idx = idx + 1;
+    end
+    while length(NSx.Data(channelIDX, :)) - thresholdTimestamps(end) < 38
+        thresholdTimestamps(end) = [];
+    end
+    newSpikes.TimeStamps(end+1:end+length(thresholdTimestamps)) = thresholdTimestamps;
+    newSpikes.Electrode(end+1:end+length(thresholdTimestamps)) = repmat(NSx.MetaTags.ChannelID(channelIDX), 1, length(thresholdTimestamps));
+    newSpikes.Unit(end+1:end+length(thresholdTimestamps)) = zeros(1, length(thresholdTimestamps));
+    if firstTimeFlag
+        newSpikes.TimeStamps(1) = [];
+        newSpikes.Electrode(1) = [];
+        newSpikes.Unit(1) = [];
+    end
+    waveformIndices = bsxfun(@plus, thresholdTimestamps', -10:37)';
+    waveformFlat = NSx.Data(channelIDX, waveformIndices(:));
+    newSpikes.Waveform(:,end+1:end+length(thresholdTimestamps)) = reshape(waveformFlat, 48, length(waveformFlat)/48);
+    if firstTimeFlag
+        newSpikes.Waveform(:,1) = [];
+        firstTimeFlag = 0;
+    end
+    clear waveformFlat;
+end
+
+[~, timestampIndex] = sort(newSpikes.TimeStamps);
+
+NEV.Data.Spikes.TimeStamp = newSpikes.TimeStamps(timestampIndex);
+NEV.Data.Spikes.Electrode = newSpikes.Electrode(timestampIndex);
+NEV.Data.Spikes.Unit = newSpikes.Unit(timestampIndex);
+NEV.Data.Spikes.Waveform = newSpikes.Waveform(:,timestampIndex);

+ 223 - 0
code/matlab_scripts/NPMK/NSx Utilities/saveChNSx.m

@@ -0,0 +1,223 @@
+function NSx = saveChNSx(varargin)
+
+% saveNSx
+% 
+% Saves a given continuous NSx file and saves a subset of the channels in
+% the given file into a new NSx file. Ths NSx file has to be opened with 
+% openNSx version 5.1.1.0 or later.
+% 
+% All input arguments are optional. Input arguments can be in any order.
+%
+%   NSx:          The data structure holding the channel information
+%
+%   fname:        Name of the file to be saved. If the fname is omitted
+%                 the program will automaticallyl save the file using the
+%                 original file name with -mod added to the end of the
+%                 file.
+%                 DEFAULT: Will automatically choose the name.
+%
+%   reset:        If argument 'reset' is passed to the function then the
+%                 channel IDs are reset. For example, when reading channels
+%                 2, 5, and 9 only, normally the file will indicate that the
+%                 newly saved file will contains channels 2, 5, and 9. If
+%                 'reset' is used, then the file will labels those channels
+%                 as 1, 2 and 3 respectively. This is a requirement for OFS
+%                 compatibility when a tetrode file is loaded.
+%                 DEFAULT: The channel labels are not reset.
+%
+%   Example: 
+%   
+%   saveChNSx('c:\data\sample.ns5', [1,5:9], 'reset');
+%
+%   In the example above, the file c:\data\sample.ns5 will be opened and
+%   channels 1,5,6,7,8,9 out of all the channels in this file will be saved
+%   as a new file. If the new file already exists then the user will be
+%   prompted if the new file should be overwritten or not. The new file
+%   will label the channels as 1, 2, 3, 4, 5, and 6.
+%
+%   Kian Torab
+%   Blackrock Microsystems
+%   kian@blackrockmicro.com
+%
+%   Version 2.1.0.1
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 2.1.0.1:
+%   - Added the flag 'reset' as an optional argument to OFS compatibility..
+%
+% 2.1.1.0:
+%   - Fixed the "numberic" bug.
+%   - Fixed saved file name bug.
+%   - Fixed other reading bugs.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Validating input arguments
+if isempty(varargin)
+    [path fname fext] = openFile;
+    channels = getChannels;
+    resetFlag = 'noreset';
+elseif length(varargin) == 1
+    if isnumeric(varargin{1})
+        [path fname fext] = openFile;
+        channels = varargin{1};
+        resetFlag = 'noreset';
+    else
+        channels = getChannels;
+        if strcmpi(varargin{1}, 'reset')
+            resetFlag = 'reset';
+        else
+            [path fname fext] = fileparts(varargin{1});
+        end
+    end
+elseif length(varargin) == 2
+    if isnumeric(varargin{1})
+        channels = varargin{1};
+        if strcmpi(varargin{2}, 'reset')
+            resetFlag = 'reset';
+            [path fname fext] = openFile;
+        else
+            [path fname fext] = fileparts(varargin{2});
+            resetFlag = 'noreset';
+        end
+    elseif strcmpi(varargin{1}, 'reset')
+        resetFlag = 'reset';
+        if isnumeric(varargin{2})
+            channels = varargin{2};
+            [path fname fext] = openFile;
+        else
+            [path fname fext] = fileparts(varargin{2});
+        end
+    else
+        [path fname fext] = fileparts(varargin{1});
+        if isnumeric(varargin{2})
+            channels = varargin{2};
+            resetFlag = 'noreset';
+        else
+            resetFlag = varargin{2};
+        end
+    end
+elseif length(varargin) == 3
+    if isnumeric(varargin{1})
+        channels = varargin{1};
+        if strcmpi(varargin{2}, 'reset')
+            resetFlag = 'reset';
+            [path fname fext] = fileparts(varargin{3});
+        else
+            [path fname fext] = fileparts(varargin{2});
+            resetFlag = varargin{3};
+        end
+    elseif strcmpi(varargin{1}, 'reset')
+        resetFlag = 'reset';
+        if isnumeric(varargin{2})
+            channels = varargin{2};
+            [path fname fext] = fileparts(varargin{3});
+        else
+            [path fname fext] = fileparts(varargin{2});
+            channels = varargin{3};
+        end
+    else
+        [path fname fext] = fileparts(varargin{1});
+        if isnumeric(varargin{2})
+            channels = varargin{2};
+            resetFlag = varargin{3};
+        else
+            resetFlag = varargin{2};
+            channels = varargin{3};
+        end
+    end
+end
+
+% Validating file name
+if fname == 0
+    disp('No file was selected.');
+    if nargout
+        clear variables;
+    end
+    return;
+end
+
+if exist(fullfile(path, [fname, fext]), 'file') ~= 2
+    disp('File cannot be found.');
+    if nargout
+        clear variables;
+    end
+    return;    
+end
+
+% Validating and fixing resetFlag input
+if ~strcmpi(resetFlag, 'reset')
+    resetFlag = 'noreset';
+end
+
+% Opening the original file
+disp('Openning the original file...');
+NSx = openNSx(fullfile(path, [fname fext]), ['c:' num2str(channels)], 'read');
+
+if NSx.RawData.PausedFile
+    disp('At this time it is not possible to extract channels from files that have pauses in them.');
+    return;
+end
+
+% Writing header into the file
+newFilename = fullfile(path, [fname '-chandec' fext]);
+if exist(newFilename, 'file') == 2
+    overwriteFlag = input('The file already exists. Overwrite? ', 's');
+    if ~strcmpi(overwriteFlag, 'y')
+        clear all;
+        return;
+    end
+end
+        
+FIDw = fopen(newFilename, 'w+', 'ieee-le');
+
+% Removing the extra channels from the header
+channelHeaderBytes = 66;
+currentPosition = length(NSx.RawData.Headers);
+totalNumberOfChannels = NSx.RawData.Headers(311);
+NSx.RawData.Headers(311) = uint8(length(channels));
+allChannels = totalNumberOfChannels:-1:1;
+thChannelToKeep = 0;
+for chanIDX = 1:totalNumberOfChannels
+    if ~ismember(allChannels(chanIDX), channels)
+        NSx.RawData.Headers(currentPosition-channelHeaderBytes+1:currentPosition) = [];
+    else
+        if strcmpi(resetFlag, 'reset')
+            NSx.RawData.Headers(currentPosition-channelHeaderBytes+3:currentPosition-channelHeaderBytes+4) = typecast(int16(length(channels)-thChannelToKeep), 'int8');
+            thChannelToKeep = thChannelToKeep + 1;
+        end
+    end
+    currentPosition = currentPosition - channelHeaderBytes;
+end
+
+% Writing the header information
+fwrite(FIDw, NSx.RawData.Headers, 'uint8');
+fwrite(FIDw, NSx.RawData.DataHeader, 'uint8');
+
+% Writing data into file
+disp('Writing into the new file...');
+fwrite(FIDw, NSx.Data, 'int16');
+fclose(FIDw);
+clear all;
+
+function [path fname fext] = openFile
+    % Getting the file name
+    if ~ismac
+        [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
+    else
+        [fname, path] = getFile('*.*', 'Choose an NSx file...');
+    end
+    fext = fname(end-3:end);
+    fname = fname(1:end-4);
+
+function channels = getChannels
+    channels = input('What channels would you like to save as a separate file? ');
+    while ~isnumeric(channels)
+        disp('The response should be a numberical value (e.g. 3 or [4,6:10]).');
+        channels = input('What channels would you like to save as a separate file? ');
+    end

+ 381 - 0
code/matlab_scripts/NPMK/NSx Utilities/saveNSx.m

@@ -0,0 +1,381 @@
+function saveNSx(NSx,varargin)
+
+%%
+% Save an .NSx file from an NSx structure (gained by using openNSx)
+% Works with file spec 2.3
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Use: saveNSx(NSx,optionalinputarguments)
+%   NSx:        The NSx data structure.
+%   All arguments below are optional:
+%   Filename:   A complete filepath for the output file.
+%               Default: CurrentFilename-Modified.NSx
+
+%saveNSx version = '1.0.0.0';
+
+
+%%
+% Verify FilePath and establish overwrite paramaters
+if not(isempty(varargin))
+    FilePath = varargin{1};
+else
+    FilePath = [fullfile(NSx.MetaTags.FilePath,NSx.MetaTags.Filename) NSx.MetaTags.FileExt];
+    [File,Path] = uiputfile;
+    FilePath = [fullfile(Path,NSx.MetaTags.Filename(1:end)),'-modified',  NSx.MetaTags.FileExt];
+end
+
+riskCompliance = 1;
+
+if riskCompliance == 0
+	disp('This script will save a new file with the proper .NSx extensions');
+	disp('but you should retain the previous file. Do you acknowledge the');
+	Accept = input('risk inherent in saving modified versions of data files? (Y/N)','s');
+	if strcmpi(Accept,'y')
+	else
+	    disp('Ending Script...');
+	    return
+	end
+end
+%%
+% Write the basic header into the file
+%FullFile
+Debug = 1;
+
+if exist(FilePath)
+        if exist(FilePath)
+        disp('File already exists!');
+        % OverwritePrompt = input('Would you like to overwrite? (Y/N)','s');
+        OverwritePrompt = 'y';
+        if strcmpi(OverwritePrompt,'y')
+            Overwrite = 1;
+            delete(FilePath);
+        else
+            return
+        end
+        end
+end
+
+clear Overwrite
+clear OverwritePrompt
+clear varargin
+
+%PausedFile?
+if iscell(NSx.Data)
+    Paused = 1;
+    NumberOfSegments = length(NSx.Data);
+else
+    Paused = 0;
+
+end
+
+FileID = fopen(FilePath, 'w', 'ieee-le');
+
+%Basic header stuff
+BytesInBasicHeader = 8+2+4+16+256+4+4+16+4;
+BytesInExtendedHeader = 2+2+16+1+1+2+2+2+2+16+4+4+2+4+4+2;
+if Paused == 1
+    for SegmentCount = 1:NumberOfSegments
+    [NumberOfChannels,LengthOfData{SegmentCount}] = size(NSx.Data{SegmentCount});
+    end
+elseif Paused == 0
+    [NumberOfChannels,LengthOfData] = size(NSx.Data);
+end
+
+
+
+%File Type ID
+    Before = 0;
+    fwrite(FileID,NSx.MetaTags.FileTypeID(1:8));
+    After = ftell(FileID);
+    if After-Before ~= 8 && Debug == 1
+        disp('error FildID')
+    end
+%File spec
+    Before = ftell(FileID);
+    fwrite(FileID, [str2double(NSx.MetaTags.FileSpec(1)) str2double(NSx.MetaTags.FileSpec(3))], 'uint8');
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error File Spec')
+    end
+%Bytes in Headers
+    Before = ftell(FileID);
+    fwrite(FileID, BytesInBasicHeader+NumberOfChannels*BytesInExtendedHeader,'uint32');
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error BytesInHeaders')
+    end
+%Label
+    Before = ftell(FileID);
+    fwrite(FileID, NSx.MetaTags.SamplingLabel);
+    After = ftell(FileID);
+    if After-Before ~= 16 && Debug == 1
+        disp('error label')
+    end
+%Comment
+    Before = ftell(FileID);
+    if ~isempty(NSx.MetaTags.Comment)
+        fwrite(FileID, NSx.MetaTags.Comment);
+    else
+        fwrite(FileID, repmat(' ', 1, 256));
+    end
+    After = ftell(FileID);
+    if After-Before ~= 256 && Debug == 1
+        disp('error comment')
+    end
+%Period
+    Before = ftell(FileID);
+    fwrite(FileID, (1/NSx.MetaTags.SamplingFreq)*30000, 'uint32');
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error period')
+    end
+%Time Resolution of time stamps
+    Before = ftell(FileID);
+    fwrite(FileID, NSx.MetaTags.TimeRes,'uint32');
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error time resolution')
+    end
+%Time Origin
+    Before = ftell(FileID);
+    if ~isempty(NSx.MetaTags.DateTimeRaw)
+        fwrite(FileID, NSx.MetaTags.DateTimeRaw,'uint16');
+    else
+        fwrite(FileID, [1900 1 1 0 0 0 0 0],'uint16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 16 && Debug == 1
+        disp('error Time Origin')
+    end
+%Channel Count
+    Before = ftell(FileID);
+    fwrite(FileID, NumberOfChannels,'uint32');
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error Channel Count')
+    end
+
+
+
+%Extended header stuff
+%Number of these equal to number of channels
+for i = 1:NumberOfChannels
+    % Type
+    Before = ftell(FileID);
+    fwrite(FileID, 'CC');
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error Type')
+    end
+    % ElectrodeID
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).ElectrodeID,'uint16');
+    catch
+        fwrite(FileID, i,'uint16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error ElectrodeID')
+    end
+    % Electrode label
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).Label);
+    catch
+        templabel = ['chan' num2str(i) '                '];
+        templabel(17:end) = [];
+        fwrite(FileID, templabel);
+    end
+    After = ftell(FileID);
+    if After-Before ~= 16 && Debug == 1
+        disp('error Electrode Label')
+    end
+    % Physical connector
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).ConnectorBank, 'uint8');
+    catch
+        if i > 0 && i <= 32
+            fwrite(FileID, 1, 'uint8');
+        elseif i > 32 && i <= 64
+            fwrite(FileID, 2, 'uint8');
+        elseif i > 64 && i <= 96
+            fwrite(FileID, 3, 'uint8');
+        elseif i > 96 && i <= 128
+            fwrite(FileID, 4, 'uint8');
+        end
+    end
+    After = ftell(FileID);
+    if After-Before ~= 1 && Debug == 1
+        disp('error Physical Connector')
+    end
+%Physical pin
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).ConnectorPin, 'uint8');
+    catch
+        fwrite(FileID, int2str((i-floor(i/32)*32)), 'uint8');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 1 && Debug == 1
+        disp('error Physical Pin')
+    end
+%Min Digital Value
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).MinDigiValue,'int16');
+    catch
+        fwrite(FileID, -32764,'int16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error min Digital Value')
+    end
+%Max Digital Value
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).MaxDigiValue,'int16');
+    catch
+        fwrite(FileID, 32764,'int16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error Max Digital value')
+    end
+%Min Analog Value
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).MinAnalogValue,'int16');
+    catch
+        fwrite(FileID, -8191,'int16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error Min Analog Value')
+    end
+%Max Analog Value
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).MaxAnalogValue,'int16');
+    catch
+        fwrite(FileID, 8191,'int16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error Max Aanalog value')
+    end
+%Units
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).AnalogUnits,'char');
+    catch
+        fwrite(FileID, 'uv              ');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 16 && Debug == 1
+        disp('error Units')
+    end
+%High Freq Corner (High frequency cutoff in mHz)
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).HighFreqCorner,'uint32');
+    catch
+        fwrite(FileID, 0,'uint32');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error High Corner')
+    end
+%High Freq Order (Order of the filter used)
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).HighFreqOrder,'uint32');
+    catch
+        fwrite(FileID, 0,'uint32');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error high Order')
+    end
+%High Filter Type (0 = none, 1 = butterworth)
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).HighFilterType,'uint16');
+    catch
+        fwrite(FileID, 0,'uint16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error High Type')
+    end
+%Low Freq Corner (Low frequency cutoff in mHz)
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).LowFreqCorner,'uint32');
+    catch
+        fwrite(FileID, 0,'uint32');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error Low Corner')
+    end
+%Low Freq Order (0 = none)
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).LowFreqOrder,'uint32');
+    catch
+        fwrite(FileID, 0,'uint32');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 4 && Debug == 1
+        disp('error Low Order')
+    end
+%Low Filter Type (0 = none, 1 = butterworth)
+    Before = ftell(FileID);
+    try
+        fwrite(FileID, NSx.ElectrodesInfo(i).LowFilterType,'uint16');
+    catch
+        fwrite(FileID, 0,'uint16');
+    end
+    After = ftell(FileID);
+    if After-Before ~= 2 && Debug == 1
+        disp('error Low Type')
+    end
+
+end
+
+
+    %DataPackets
+if Paused == 0
+    %Header
+    fwrite(FileID, NSx.RawData.DataHeader(1));
+    %Timestamp
+    fwrite(FileID, NSx.MetaTags.Timestamp,'uint32');
+    %Number of data points
+    fwrite(FileID, LengthOfData, 'uint32');
+
+    TotalDataPoints = LengthOfData * NumberOfChannels;
+    %for i = 1:TotalDataPoints
+    %Data points
+    %fwrite(FileID, NSx.Data(i),'int16');
+    fwrite(FileID, NSx.Data,'int16');
+    %end
+elseif Paused == 1
+    for SegmentNumber = 1:NumberOfSegments
+        %Header
+        fwrite(FileID, NSx.RawData.DataHeader(1+9*(SegmentNumber-1)));
+        %Timestamp
+        fwrite(FileID, NSx.MetaTags.Timestamp(SegmentNumber),'uint32');
+        %Number of data points
+        fwrite(FileID, LengthOfData{SegmentNumber}, 'uint32');
+
+        TotalDataPoints = LengthOfData{SegmentNumber} * NumberOfChannels;
+        %for i = 1:TotalDataPoints
+        %Data points
+        %fwrite(FileID, NSx.Data(i),'int16');
+        fwrite(FileID, NSx.Data{SegmentNumber},'int16');
+        %end
+    end
+end
+
+fclose(FileID);

+ 8 - 0
code/matlab_scripts/NPMK/NSx Utilities/separatePausedNSx.m

@@ -0,0 +1,8 @@
+function separatePausedNSx(varargin)
+
+% separatePausedNsx    Obsoleted. Use splitNSxPauses instead.
+
+disp('This function is obsoleted.')
+disp('Use splitNSxPauses instead.');
+
+splitNSxPauses;

+ 89 - 0
code/matlab_scripts/NPMK/NSx Utilities/separatePausedNSx_old.m

@@ -0,0 +1,89 @@
+function separatePausedNSx(varargin)
+
+% separatePausedNsx    Saves paused data segments from a single NSx file 
+%                      as individual NSx files
+%
+%    separatePausedNSx(FILENAME) where FILENAME has N paused segments
+%    will create N individual files with the same extension named
+%    FILENAME-1, FILENAME-2, ..., FILENAME-N.
+%
+%    separatePausedFiles without any input arguments opens a UIgetfile to
+%    select the NSx file to separate
+%
+%    Brett Dowden
+%    bdowden@blackrockmicro.com
+%    Nick Halper
+%    nhalper@blackrockmicro.com
+%    Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: Initial release
+%
+% 1.1.0.0:
+%   - Fixed a broken function that dependent on a non-existant saveNEV
+%   script.
+%
+% 1.2.0.0:
+%   - Corrected  NSx_out.MetaTags.Filename     =
+%   [NSx.MetaTags.Filename(1:end) '-p' sprintf('%03d', i)
+%   NSx.MetaTags.FileExt] which was incorrectly removing the last 4
+%   characters of the filename in an attempt to remove the extension.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Since openNSx checks input parameters for file validity and for no input
+% argument case, just pass varargin to openNSx
+NSx = openNSx('read',varargin{:});
+
+% Check to see if there were pauses in the file.  If so, save the sections
+% as individual files, if not just report that to the user and end function
+if length(NSx.MetaTags.Timestamp) == 1
+    disp('No pauses in data file.  No action taken');
+else
+    for i = 1 : length(NSx.MetaTags.Timestamp)
+        % create a copy of NSx, except with only one data segment and the
+        % corresponding Timestamp, DataPoints, and NumofPacket fields
+        NSx_out.MetaTags              = NSx.MetaTags;
+        NSx_out.MetaTags.Timestamp    = NSx.MetaTags.Timestamp(i);
+        NSx_out.MetaTags.DataPoints   = NSx.MetaTags.DataPoints(i);
+        NSx_out.MetaTags.NumofPackets = NSx.MetaTags.DataPoints(i);
+        
+        NSx_out.ElectrodesInfo        = NSx.ElectrodesInfo;
+        
+        NSx_out.Data                  = NSx.Data{i};
+        NSx_out.RawData.Headers       = NSx.RawData.Headers;
+        %Data headers are only 9 bytes, so only check for the correct,
+        %respective 9 bytes
+        NSx_out.RawData.DataHeader    = NSx.RawData.DataHeader(1+(9*(i-1)):9+(9*(i-1)));
+        
+        % Create enumerated file name
+        NSx_out.MetaTags.Filename     = [NSx.MetaTags.Filename(1:end) '-p' sprintf('%03d', i) NSx.MetaTags.FileExt];
+        disp('Opening the original file...');
+
+
+% Check for filename existence
+newFilename = fullfile(NSx.MetaTags.FilePath, NSx_out.MetaTags.Filename);
+if exist(newFilename, 'file') == 2
+    overwriteFlag = input('The file already exists. Overwrite? ', 's');
+    if ~strcmpi(overwriteFlag, 'y')
+        return;
+    end
+end
+        
+
+% Create new file
+FIDw = fopen(newFilename, 'w+', 'ieee-le');
+
+
+% Writing the header information
+fwrite(FIDw, NSx_out.RawData.Headers, 'uint8');
+fwrite(FIDw, NSx_out.RawData.DataHeader, 'uint8');
+
+
+% Writing data into file
+disp('Writing into the new file...');
+fwrite(FIDw, NSx_out.Data, 'int16');
+fclose(FIDw);
+    end
+    clear all;
+end

+ 126 - 0
code/matlab_scripts/NPMK/NSx Utilities/splitNSx.m

@@ -0,0 +1,126 @@
+function splitNSx(splitCount)
+
+% splitNSx
+% 
+% Opens and splits an NSx file in smaller pieces, timewise.
+%
+% Use splitNSx(splitCount)
+% 
+% All input arguments are optional. Input arguments can be in any order.
+%
+%   splitCount:   Defines the number of splits.
+%                 DEFAULT: Splits the file in 2 pieces.
+%
+%   Example 1: 
+%   splitNSx(4);
+%
+%   In the example above, the user will be prompted to select a file. The
+%   loaded file will be split in 4 samller files. For example, if the file
+%   is 1 hour long then it will be split into four 15-minute files.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 1.1.0.0:
+%   - Fixed a bug related to a case where initial timestamp of the first
+%     data segment was not 0. 
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+
+% Validating input parameter
+if ~exist('splitCount', 'var')
+    splitCount = 2;
+end
+
+% Getting the file name
+if ~ismac
+    [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
+else
+    [fname, path] = getFile('*.*', 'Choose an NSx file...');
+end
+if fname == 0
+    disp('No file was selected.');
+    if nargout
+        clear variables;
+    end
+    return;
+end
+fext = fname(end-3:end);
+    
+% Loading the file
+%% Reading Basic Header from file into NSx structure.
+FID                       = fopen([path fname], 'r', 'ieee-le');
+NSx.MetaTags.Filename     = fname;
+NSx.MetaTags.FilePath     = path(1:end-1);
+NSx.MetaTags.FileExt      = fext;
+NSx.MetaTags.FileTypeID   = fread(FID, [1,8]   , '*char');
+disp(['Splitting the NSx file in ' num2str(splitCount) ' pieces...']);
+if strcmpi(NSx.MetaTags.FileTypeID, 'NEURALSG')
+    disp('File type 2.1 is not yet implemented.');
+    %NOT IMPLEMENTED YET
+%     fseek(FID, 0, 'bof');
+%     header = fread(FID, 314,'*uint8');
+%     positionEOH = ftell(FID);
+%     fseek(FID, 0, 'eof');
+%     positionEOD = ftell(FID);
+%     dataLength = positionEOD - positionEOH;
+%     fseek(FID, 28, 'bof');
+%     channelCount = fread(FID, 1       , 'uint32=>double');
+elseif strcmpi(NSx.MetaTags.FileTypeID, 'NEURALCD')
+    % Calculating different points in the file
+    fseek(FID, 0, 'bof');
+    basicHeader = fread(FID, 314, '*uint8');
+    positionEOE = typecast(basicHeader(11:14), 'uint32');
+    fseek(FID, 0, 'eof');
+    positionEOD = ftell(FID);
+    % Calculating channelCount, data Length
+    channelCount = typecast(basicHeader(311:314), 'uint32');
+    dataLength = positionEOD - positionEOE - 9;
+    % Reading the number of packets
+    fseek(FID, 28, 'bof');
+    numOfPackets = (dataLength)/(2*channelCount);
+    % Calculating the number of bytes in each segment
+    segmentBytes = floor(numOfPackets/splitCount)*(2*channelCount);
+    % Reading the headers and the data header
+    fseek(FID, 0, 'bof');
+    fileHeader = fread(FID, positionEOE, 'char');
+    dataHeader = fread(FID, 9, 'char');
+	fseek(FID, positionEOE+9, 'bof');
+    for idx = 1:splitCount
+        % Opening a file for saving
+        FIDw = fopen([path fname(1:end-4) '-s' sprintf('%03d', idx) fname(end-3:end)], 'w+', 'ieee-le');
+        fprintf('\nReading segment %d... ', idx);
+        % Reading the segment
+        dataSegment = fread(FID, segmentBytes, 'char');
+        fprintf('Writing segment %d... ', idx);
+        % Writing the segmented data into file
+        fwrite(FIDw, fileHeader, 'char');
+        % Set the timestamp of the segments 2+ to 0 so there's no
+        % introduced shift by openNSx.
+        if idx > 1
+            dataHeader(2:5) = 0;
+        end
+        fwrite(FIDw, dataHeader, 'char');
+        fwrite(FIDw, dataSegment, 'char');
+        % Clearing variables and closing file
+        clear dataSegment;
+        fclose(FIDw);
+    end
+    fprintf('\n');
+else
+    % Display error if non-compatible file is trying to open.
+    disp('This version of splitNSx can only split File Specs 2.2 and 2.3');
+    disp(['The selected file spec is ' NSx.MetaTags.FileSpec '.']);
+    fclose(FID);
+    clear variables;
+    return;
+end

+ 133 - 0
code/matlab_scripts/NPMK/NSx Utilities/splitNSxPauses.m

@@ -0,0 +1,133 @@
+function splitNSxPauses(fileName)
+
+% splitNSxPauses
+% 
+% Opens and splits an NSx file in smaller pieces, timewise.
+%
+% Use splitNSx(fileName)
+% 
+% All input arguments are optional. Input arguments can be in any order.
+%
+%   fileName:   File name of the file that needs to be split.
+%               DEFAULT: The user will be prompted to select a file.
+%
+%   Example 1: 
+%   splitNSx('C:\Datafolder\mydata.ns5');
+%
+%   In the example above, the file C:\Datafolder\mydata.ns5 will be opened.
+%   The loaded file will be split in samller files representing its paused 
+%   sub-segments.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Version History
+%
+% 1.0.0.0: August 31, 2016
+%   - Initial release.
+%   - Successor to separateNSxPaused running much more memory efficient.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Getting the file name
+if ~exist('fileName', 'var')
+    fileName = '';
+end
+
+if ~(exist(fileName, 'file') == 2)
+    if ~ismac
+        [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
+    else
+        [fname, path] = getFile('*.*', 'Choose an NSx file...');
+    end
+    if fname == 0
+        disp('No file was selected.');
+        if nargout
+            clear variables;
+        end
+        return;
+    end
+    fext = fname(end-3:end);
+else
+    [path, fname, fext] = fileparts(fileName);
+    if ismac path = [path '/']; else path = [path '\']; end
+    fname = [fname fext];
+end
+
+%% Getting header information
+NSx = openNSx('noread', [path fname ]);
+    
+% Loading the file
+%% Reading Basic Header from file into NSx structure.
+FID                       = fopen([path fname], 'r', 'ieee-le');
+NSx.MetaTags.Filename     = fname;
+NSx.MetaTags.FilePath     = path(1:end-1);
+NSx.MetaTags.FileExt      = fext;
+NSx.MetaTags.FileTypeID   = fread(FID, [1,8]   , '*char');
+if strcmpi(NSx.MetaTags.FileTypeID, 'NEURALSG')
+    disp('File type 2.1 is not yet implemented.');
+    %NOT IMPLEMENTED YET
+%     fseek(FID, 0, 'bof');
+%     header = fread(FID, 314,'*uint8');
+%     positionEOH = ftell(FID);
+%     fseek(FID, 0, 'eof');
+%     positionEOD = ftell(FID);
+%     dataLength = positionEOD - positionEOH;
+%     fseek(FID, 28, 'bof');
+%     channelCount = fread(FID, 1       , 'uint32=>double');
+elseif strcmpi(NSx.MetaTags.FileTypeID, 'NEURALCD')
+    % Calculating different points in the file
+    fseek(FID, 0, 'bof');
+    basicHeader = fread(FID, 314, '*uint8');
+    positionEOE = typecast(basicHeader(11:14), 'uint32');
+    fseek(FID, 0, 'eof');
+    positionEOD = ftell(FID);
+    % Calculating channelCount, data Length
+    channelCount = typecast(basicHeader(311:314), 'uint32');
+    dataLength = positionEOD - positionEOE - 9;
+    % Reading the number of packets
+    fseek(FID, 28, 'bof');
+    numOfPackets = (dataLength)/(2*channelCount);
+    % Calculating the number of splits
+    splitCount = length(NSx.MetaTags.Timestamp);
+    % Calculating the number of bytes in each segment
+    segmentBytes = NSx.MetaTags.DataPoints * 2 * double(channelCount);
+    % Reading the headers and the data header
+    fseek(FID, 0, 'bof');
+    fileHeader = fread(FID, positionEOE, 'char');
+    dataHeader = fread(FID, 9, 'char');
+	fseek(FID, positionEOE, 'bof');
+    disp(['Splitting the NSx file in ' num2str(splitCount) ' pieces...']);
+    for idx = 1:splitCount
+        % Opening a file for saving
+        FIDw = fopen([path fname(1:end-4) '-s' sprintf('%03d', idx) fname(end-3:end)], 'w+', 'ieee-le');
+        fprintf('\nReading segment %d... ', idx);
+        % Reading the segment
+        fseek(FID, 9, 'cof'); % Skipping the data header
+        dataSegment = fread(FID, segmentBytes(idx), 'char');
+        fprintf('Writing segment %d... ', idx);
+        % Writing the segmented data into file
+        fwrite(FIDw, fileHeader, 'char');
+        % Set the timestamp of the segments 2+ to 0 so there's no
+        % introduced shift by openNSx.
+        if idx > 1
+            dataHeader(2:5) = 0;
+        end
+        fwrite(FIDw, dataHeader, 'char');
+        fwrite(FIDw, dataSegment, 'char');
+        % Clearing variables and closing file
+        clear dataSegment;
+        fclose(FIDw);
+    end
+    fprintf('\n');
+else
+    % Display error if non-compatible file is trying to open.
+    disp('This version of splitNSx can only split File Specs 2.2 and 2.3');
+    disp(['The selected file spec is ' NSx.MetaTags.FileSpec '.']);
+    fclose(FID);
+    clear variables;
+    return;
+end

BIN
code/matlab_scripts/NPMK/NTrode Utilities/.DS_Store


+ 28 - 0
code/matlab_scripts/NPMK/NTrode Utilities/ntrodeGroups.m

@@ -0,0 +1,28 @@
+function output = ntrodeGroups(ccf)
+
+% ntrodeGroups
+%
+% This script takes in a CCF file and displays the information on the
+% ntrode groups within the data file.
+%
+%   ccf:       Pass the CCF of interest. If no CCF is passed, the user will
+%              be prompted to choose a CCF file.
+%              DEFAULT: Will open Open File UI.
+%    
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.1.0.0
+%
+
+
+
+if ~exist('ccf', 'var')
+    ccf = openCCF;
+end
+
+for idx = 1:length(ccf.NTrodeInfo.NTrodeID)
+    fprintf('NTrode group %d members: %s\n', idx, int2str(ccf.NTrodeInfo.NTrodeMembers{idx}));
+end
+
+output = ccf.NTrodeInfo.NTrodeMembers;

+ 80 - 0
code/matlab_scripts/NPMK/NTrode Utilities/saveNEVTetrodes.m

@@ -0,0 +1,80 @@
+function saveNEVTetrodes(NEVFullFilename)
+
+% saveNEVTetrodes
+% 
+% Opens saves a new NEV file and splits it into smaller NEV files
+% containing only the tetrodes according to the associated CCF file. The
+% CCF file should have the same name as the data file.
+%
+% NEVFullFilename:  The full path to the NEV to be opened.
+%                   DEFAULT: If the filename is not provided, the user will
+%                   be prompted to select a file.
+%
+% Use saveNEVTetrodes(NEVFullFilename)
+%
+%   Example: saveNEVTetrodes('c:\datafolder\datafile.nev');
+%
+%   The function will open datafile.nev and datafile.ccf and based on the
+%   tetrode information saved in datafile.ccf, it will split datafile.nev
+%   into smaller chunks that will only contain channels associated to that
+%   particular tetrode.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.0.0.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Opening the file
+if ~exist('NEVFullFilename', 'var')
+    [dataFilename dataFolder] = getFile('*.nev');
+    NEVFullFilename = [dataFolder dataFilename];
+elseif exist(NEVFullFilename, 'file') ~= 2
+        disp('The NEV file name does not exist.');
+        return;
+else
+    [filepath filename fileext] = fileparts(NEVFullFilename);
+    dataFolder = [filepath '/'];
+    dataFilename = [filename fileext];
+end
+    
+
+%% Openning the associated CCF file    
+ccfFullFilename = [dataFolder dataFilename(1:end-3) 'ccf'];
+if exist(ccfFullFilename, 'file') ~= 2 % for 2.x file type
+    ccfFullFilename = [dataFolder dataFilename(1:end-8) '.ccf'];
+    if exist(ccfFullFilename, 'file') ~= 2 % for TOC file type
+        disp('Cannot find the associated CCF file.');
+        disp('This function requires the CCF file used during the recording.');
+        disp('The CCF must have the same name as the original recorded file.');
+        return;
+    end
+end
+ccf = openCCF(ccfFullFilename);
+
+% Calculating the number of NTrode groups in the file
+if isfield(ccf, 'NTrodeInfo')
+    if isfield(ccf.NTrodeInfo, 'NTrodeMembers')
+        numberOfNTrodeGroups = size(ccf.NTrodeInfo.NTrodeMembers,2);
+    else
+        disp('This data file does not contain any tetrodes.');
+        return;
+    end
+else
+    disp('There is an error in the CCF file.');
+    return;
+end
+
+% Splitting the data file according to the information saved in the
+% associated CCF file.
+for idx = 1:numberOfNTrodeGroups
+    fprintf('Saving tetrode %d containing channels %s.\n', idx, num2str(ccf.NTrodeInfo.NTrodeMembers{idx}));
+    saveNEVSubSpikes(ccf.NTrodeInfo.NTrodeMembers{idx}, NEVFullFilename, 'tet');
+end

+ 68 - 0
code/matlab_scripts/NPMK/NTrode Utilities/splitNEVNTrode.m

@@ -0,0 +1,68 @@
+function splitNSxNTrode
+
+% splitNEVNTrode
+%
+% Opens and splits an NEV file based on its NTrode groups. It depends on
+% openCCF file.
+%
+% Use splitNEVNTrode
+%
+% This function does not take any inputs.
+%
+%   Example 1:
+%   splitNEVNTrode;
+%
+%   In the example above, the user will be prompted to select a CCF file
+%   first. The CCF contains the ntrode grouping infromation. Then the user
+%   will be prompted to select a NEV file. The script will then split the
+%   NEV file into smaller NEV files containing channels in given ntrode
+%   groups. For example, if ntrode group one consists of channels 1,3,5,
+%   and 12, then using splitNEVNTrode will split the file into a smaller
+%   NEV files that contains those channels only. If there are multiple
+%   ntrodes then the files will split into multiple smaller files, equal in
+%   number of the ntrode groups.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%   Kian Torab
+%   support@blackrockmicro.com
+%   Blackrock Microsystems
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0: January 18, 2016
+%   - Initial release.
+%
+% 1.1.0.0: October 10, 2016 - Saman Hagh Gooie
+%   - Bug fixes with file loading
+%   - Fixed the file extension used for saving
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Validating input parameter
+ccf = openCCF;
+splitCount = length(ccf.NTrodeInfo.NTrodeID);
+
+% Getting the file name
+if ~ismac
+    [fname, path] = getFile('*.nev', 'Choose an NEV file...');
+else
+    [fname, path] = getFile('*.nev', 'Choose an NEV file...');
+end
+
+if fname == 0
+    disp('No file was selected.');
+    if nargout
+        clear variables;
+    end
+    return;
+end
+fext = fname(end-3:end);
+
+% Loading the file
+for idx = 1:splitCount
+    % Determining whether tetrode channel is recorded and valid in NSx
+    tetrodeChannels = ccf.NTrodeInfo.NTrodeMembers{idx};
+    NEV = openNEV([path, fname(1:end-4) '.nev'], ['c:' num2str(tetrodeChannels)]); % modified by SH 05-Oct-2016
+    newFileName = [path fname(1:end-4) '-tet' sprintf('%03d', idx) fname(end-3:end)];
+    saveNEV(NEV, newFileName, 'noreport');
+end

+ 139 - 0
code/matlab_scripts/NPMK/NTrode Utilities/splitNSxNTrode.m

@@ -0,0 +1,139 @@
+function splitNSxNTrode
+
+% splitNSxNTrode
+% 
+% Opens and splits an NSx file based on its NTrode groups. It depends on
+% openCCF file.
+%
+% Use splitNSxNTrode
+% 
+% This function does not take any inputs.
+%
+%   Example 1: 
+%   splitNSxNTrode;
+%
+%   In the example above, the user will be prompted to select a CCF file
+%   first. The CCF contains the ntrode grouping infromation. Then the user
+%   will be prompted to select a NSx file. The script will then split the
+%   NSx file into smaller NSx files containing channels in given ntrode
+%   groups. For example, if ntrode group one consists of channels 1,3,5,
+%   and 12, then using splitNSxNTrode will split the file into a smaller
+%   NSx file that contains those channels only. If there are multiple
+%   ntrodes then the files will split into multiple smaller files, equal in
+%   number of the ntrode groups.
+%
+%   Kian Torab
+%   ktorab@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.0.1.0
+%
+
+% Validating input parameter
+ccf = openCCF;
+splitCount = length(ccf.NTrodeInfo.NTrodeID);
+
+% Getting the file name
+if ~ismac
+    [fname, path] = getFile('*.ns*', 'Choose an NSx file...');
+else
+    [fname, path] = getFile('*.*', 'Choose an NSx file...');
+end
+if fname == 0
+    disp('No file was selected.');
+    if nargout
+        clear variables;
+    end
+    return;
+end
+fext = fname(end-3:end);
+    
+% Loading the file
+%% Reading Basic Header from file into NSx structure.
+FID                       = fopen([path fname], 'r', 'ieee-le');
+NSx.MetaTags.Filename     = fname;
+NSx.MetaTags.FilePath     = path(1:end-1);
+NSx.MetaTags.FileExt      = fext;
+NSx.MetaTags.FileTypeID   = fread(FID, [1,8]   , '*char');
+disp(['Splitting the NSx file in ' num2str(splitCount) ' pieces...']);
+if strcmpi(NSx.MetaTags.FileTypeID, 'NEURALSG')
+    disp('File type 2.1 is not yet implemented.');
+    %NOT IMPLEMENTED YET
+%     fseek(FID, 0, 'bof');
+%     header = fread(FID, 314,'*uint8');
+%     positionEOH = ftell(FID);
+%     fseek(FID, 0, 'eof');
+%     positionEOD = ftell(FID);
+%     dataLength = positionEOD - positionEOH;
+%     fseek(FID, 28, 'bof');
+%     channelCount = fread(FID, 1       , 'uint32=>double');
+elseif strcmpi(NSx.MetaTags.FileTypeID, 'NEURALCD')
+    % Calculating different points in the file
+    fseek(FID, 0, 'bof');
+    basicHeader = fread(FID, 314, '*uint8');
+    positionEOB = ftell(FID);
+    positionEOE = typecast(basicHeader(11:14), 'uint32');
+    fseek(FID, 0, 'eof');
+    positionEOD = ftell(FID);
+    
+    % Calculating channelCount, data Length
+    channelCount = typecast(basicHeader(311:314), 'uint32');
+    dataLength = positionEOD - positionEOE - 9;
+    
+    % Reading extended header and calculating channel IDs
+    fseek(FID, positionEOB, 'bof');
+    extHeader = fread(FID, [(positionEOE-positionEOB)/channelCount, channelCount], '*uint8');
+ 
+    % Reading the channel IDs. This only wokrs for as long as channel IDs
+    % are 8-bit integers. If they change, a typecast of 3:4 is necessasry
+    channelID = extHeader(3,1:channelCount);
+    
+    % Reading the number of packets
+    fseek(FID, 28, 'bof');
+   
+    % Calculating the number of bytes in each segment
+    channelBytes = (dataLength)/channelCount;
+
+    % Reading the headers and the data header
+    fseek(FID, 0, 'bof');
+    fileHeader = fread(FID, positionEOE, 'char');
+    dataHeader = fread(FID, 9, 'char');
+	fseek(FID, positionEOE+9, 'bof');
+
+    % Reading the data
+    fprintf('\nReading the entire data file...\n');
+    dataSegment = fread(FID, [channelCount, channelBytes], 'int16');
+       
+    for idx = 1:splitCount
+        % Determining whether tetrode channel is recorded and valid in NSx
+        tetrodeChannels = ccf.NTrodeInfo.NTrodeMembers{idx};
+        for tetIDX = 1:length(tetrodeChannels)
+            validChannel = find(channelID == tetrodeChannels(tetIDX)); 
+            if isempty(validChannel)
+                fprintf(2,'The tetrode channel %1.0f from tetrode group %d does not exist in the continuous file.\n',tetrodeChannels(tetIDX), idx);
+                break;
+            end
+            validChannels(tetIDX) = validChannel;
+        end
+        if ~isempty(validChannel)
+            % Opening a file for saving
+            fprintf('Writing segment %d...\n', idx);
+            FIDw = fopen([path fname(1:end-4) '-tet' sprintf('%03d', idx) fname(end-3:end)], 'w+', 'ieee-le');
+        
+            % Writing the segmented data into file
+            basicHeader(end-3) = length(validChannels);
+            fwrite(FIDw, basicHeader, 'char');
+            fwrite(FIDw, extHeader(:,validChannels), 'char');
+            fwrite(FIDw, dataHeader, 'char');
+            fwrite(FIDw, dataSegment(validChannels,:), 'int16');
+            fclose(FIDw);
+        end
+    end
+    fprintf('\n');
+else
+    % Display error if non-compatible file is trying to open.
+    disp('This version of splitNSx can only split File Specs 2.2 and 2.3');
+    disp(['The selected file spec is ' NSx.MetaTags.FileSpec '.']);
+    fclose(FID);
+    clear variables;
+    return;
+end

+ 23 - 0
code/matlab_scripts/NPMK/Other tools/.svn/all-wcprops

@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svnroot/npmk/!svn/ver/29/Other%20tools
+END
+kshuffle.m
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/npmk/!svn/ver/16/Other%20tools/kshuffle.m
+END
+offline2Struct.m
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svnroot/npmk/!svn/ver/29/Other%20tools/offline2Struct.m
+END
+playSound.m
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svnroot/npmk/!svn/ver/16/Other%20tools/playSound.m
+END

+ 130 - 0
code/matlab_scripts/NPMK/Other tools/.svn/entries

@@ -0,0 +1,130 @@
+10
+
+dir
+46
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk/Other%20tools
+https://kianabc@npmk.svn.sourceforge.net/svnroot/npmk
+
+
+
+2011-04-04T18:43:18.688072Z
+29
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+393bbe0d-84b2-4775-9cca-1b2fa99bc5f5
+
+kshuffle.m
+file
+
+
+
+
+2012-03-27T23:33:00.000000Z
+00f9f15e4f240eefa7cd24e389c26e2a
+2010-12-23T18:31:46.434135Z
+16
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+569
+
+offline2Struct.m
+file
+
+
+
+
+2012-03-27T23:33:00.000000Z
+557cc3aeaebd4bc737e45c1430ae6ae5
+2011-04-04T18:43:18.688072Z
+29
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+400
+
+playSound.m
+file
+
+
+
+
+2012-03-27T23:33:00.000000Z
+108f86cad26e84ef58715ca840b4ed7f
+2010-12-23T18:31:46.434135Z
+16
+kianabc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2712
+

+ 21 - 0
code/matlab_scripts/NPMK/Other tools/.svn/text-base/kshuffle.m.svn-base

@@ -0,0 +1,21 @@
+function shuffledArray = kshuffle(inputArray, DIM)
+
+%
+%   shuffledArray = kshuffle(inputArray, DIM)
+%
+%   Shuffles a matrix by row or column dimension.
+%
+%   Kian Torab
+%   kian.torab@utah.edu
+%   Department of Bioengineering
+%   University of Utah
+%   Version 1.1.0 - March 4, 2010
+
+switch DIM
+    case 'row'
+        shuffledArray = inputArray(randperm(size(inputArray, 1)), :);
+    case 'column'
+        shuffledArray = inputArray(:, randperm(size(inputArray, 2)));
+    otherwise
+        disp('DIM is invalid. See HELP for more information.');
+end

+ 16 - 0
code/matlab_scripts/NPMK/Other tools/.svn/text-base/offline2Struct.m.svn-base

@@ -0,0 +1,16 @@
+%% Converts offline sorter variables into a structure for easy MATLAB manipulation
+%
+%  Kian Torab
+%  ktorab@blackrockmicro.com
+%  Blackrock Microsystems
+
+
+for i = 1:96
+    ChannelName = ['Chan', num2str(i, '%03.0f')];
+    if exist(ChannelName, 'var')
+        VariableName = eval(ChannelName);
+        Channels.(['Chan', num2str(i, '%3.0f')]) = VariableName;
+    end
+end
+
+clear Chan0*;

+ 94 - 0
code/matlab_scripts/NPMK/Other tools/.svn/text-base/playSound.m.svn-base

@@ -0,0 +1,94 @@
+% Plays a predefined sound. Possible options are:
+%
+%   failure
+%   abort
+%   gocue
+%   alert
+%   warning
+%   error
+%   done
+%   list     - will list names for all the available sounds
+%
+% Example: playSound('alert')
+%
+%   Kian Torab
+%   kian.torab@utah.edu
+%   Department of Bioengineering
+%   University of Utah
+%   Version 1.2.0 - February 26, 2010
+
+function playSound(soundType)
+
+availableSounds = {'failure',...
+                   'abort',...
+                   'gocue',...
+                   'alert',...
+                   'warning',...
+                   'done',...
+                   'error'};
+
+if ~exist('soundType', 'var')
+    disp('Please specify a sound type.');
+    return;
+end
+
+Freq1   = 0.1;
+Freq2   = 0.05;
+Freq3   = 0.175;
+Freq4   = 0.5;
+AmpFrac = 0.5;
+FS      = 22050;
+%% Failure Sound
+FailureSound = [AmpFrac*sin(0:Freq1:Freq1*4000),...
+                AmpFrac*sin(0:Freq2:Freq2*10000)]; 
+%% Abort Sound
+AbortSound   =  AmpFrac*sin(0:Freq2:Freq2*10000);
+%% GoCue Sound
+GoSound      =  AmpFrac*sin(0:Freq3:Freq3*1000); 
+%% Alert Sound
+AlertSound   =  AmpFrac*sin(0:Freq4:Freq4*100);
+%% Warning Sound
+WarningSound =  AmpFrac*sin(0:Freq4:Freq3*10000);
+%% Error Sound
+TempSound1 = AmpFrac * sin(0:Freq2*1:Freq2*1*6000);
+TempSound2 = AmpFrac * sin(0:Freq2*2:Freq2*2*6000);
+TempSound3 = AmpFrac * sin(0:Freq2*3:Freq2*3*6000);
+ErrorSound = horzcat(TempSound1, TempSound2, TempSound3);
+%% Done Sound
+quarterBeat = 0.018*6000;
+baseFreq = 0.015;
+TempSound1 = AmpFrac * sin(0:baseFreq+0.070*1:quarterBeat*4);
+TempSound2 = AmpFrac * sin(0:baseFreq+0.050*1:quarterBeat*2);
+TempSound3 = AmpFrac * sin(0:baseFreq+0.050*1:quarterBeat*2);
+TempSound4 = AmpFrac * sin(0:baseFreq+0.057*1:quarterBeat*4);
+TempSound5 = AmpFrac * sin(0:baseFreq+0.050*1:quarterBeat*8);
+TempSound6 = AmpFrac * sin(0:baseFreq+0.065*1:quarterBeat*4);
+TempSound7 = AmpFrac * sin(0:baseFreq+0.070*1:quarterBeat*8);
+DoneSound = horzcat(TempSound1, TempSound2, TempSound3,...
+                    TempSound4, TempSound5, TempSound6,...
+                    TempSound7);
+
+switch lower(soundType)
+    case 'failure'
+        playSound = FailureSound;
+    case 'abort'
+        playSound = AbortSound;
+    case 'gocue'
+        playSound = GoSound;
+    case 'alert'
+        playSound = AlertSound;
+    case 'warning'
+        playSound = WarningSound;
+    case 'done'
+        playSound = DoneSound;
+    case 'error'
+        playSound = ErrorSound;
+    case 'list'
+        disp(availableSounds);
+        return;
+    otherwise
+        disp('Sound type is not valid. Use ''help playSound'' for more information.');
+        return;
+end
+
+wavplay(playSound, FS);

+ 84 - 0
code/matlab_scripts/NPMK/Other tools/edgeDetect.m

@@ -0,0 +1,84 @@
+function timestamps = edgeDetect(signal, threshold, type)
+
+% edgeDetect
+% 
+% Detects rising or falling edges of a signal whenever the signal crosses
+% the threshold.
+%
+%
+% Use timestamps = edgeDetect(signal, threshold, type)
+% 
+% Variables fname and threshold are optional.
+%
+%   signal:       Name of the file to be opened. If the fname is omitted
+%                 the user will be prompted to select a file. 
+%
+%   threshold:    The value used for threshold crossings. This function
+%                 will detect when the signal crosses this value.
+%                 DEFAULT: It will automatically choose the threshold at
+%                 80% of the maximum value in the signal.
+%
+%
+%   type:         Contains the points in the signal where the threshold
+%                 crossing occurs.
+%                 DEFAULT: It will find the rising edges.
+%
+%   Example 1: 
+%   timestamps = edgeDetect(signal, 1000);
+%
+%   In the example above, the points where signal crosses value 1000 
+%   (rising edge) is detected and returned in variable timestamps.
+%
+%   timestamps = edgeDetect(signal, 1000, 'falling');
+%
+%   In the example above, the points where signal crosses value 1000 
+%   (falling edge) is detected and returned in variable timestamps.
+%
+%   Kian Torab
+%   kian@blackrockmicro.com
+%   Blackrock Microsystems
+%   Version 1.1.0.0
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Version History
+%
+% 1.0.0.0:
+%   - Initial release.
+%
+% 1.1.0.0:
+%   - Added automatic edge detection.
+%   - Updated help.
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Validations
+
+% Validating input arguments.
+if nargin < 1 || nargin > 3
+    disp('Invalid number of input arguments. Use ''help edgeDetect'' for more information.');
+    return;
+end
+
+if ~exist('threshold', 'var')
+    threshold = 0.8 * max(signal);
+    disp(['Threshold was not provided. It wss automatically calculated and set at ' num2str(threshold) '.']);
+end
+
+% Validating variable 'type'
+if ~exist('type', 'var')
+    type = 'rising';
+end
+
+% Validating type and determining the threshold crossing points
+if strcmpi(type, 'rising')
+    timestamps = signal>threshold;
+elseif strcmpi(type, 'falling')
+    timestamps = signal<threshold;
+else
+    disp('Type does not exist. Please type ''help edgeDetect'' to see all available types.');
+    timestamps = 0;
+    return;
+end
+
+% Finding all the points where the signal crosses the threshold
+timestamps = diff(timestamps);
+timestamps = find(timestamps==1);

+ 0 - 0
code/matlab_scripts/NPMK/Other tools/kshuffle.m


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov