diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile
index 1ae639259f1f18b1eb130ca3d6080c81bb120444..398b848f09296e44d13bd7e8ec4cdfe4a968c47a 100644
--- a/Builds/Linux/Makefile
+++ b/Builds/Linux/Makefile
@@ -18,10 +18,10 @@ ifeq ($(CONFIG),Debug)
     TARGET_ARCH := -march=native
   endif
 
-  CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=0.4.2" -D "JUCE_APP_VERSION_HEX=0x402" -I /usr/include -I /usr/include/freetype2 -I ~/SDKs/VST3\ SDK -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I JuceLibraryCode/
+  CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=0.4.2.1" -D "JUCE_APP_VERSION_HEX=0x40201" -I /usr/include -I /usr/include/freetype2 -I ~/SDKs/VST3\ SDK -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I JuceLibraryCode/
   CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O3 -rdynamic -fvisibility=hidden
   CXXFLAGS += $(CFLAGS) -std=c++11
-  LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -L/usr/local/include -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -ldl -lXext -lGLU -rdynamic -fPIC
+  LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -L/usr/local/include -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -ldl -lXext -lGLU -rdynamic -fPIC -Wl,-rpath,'$$ORIGIN'
 
   TARGET := open-ephys
   BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)
@@ -38,10 +38,10 @@ ifeq ($(CONFIG),Release)
     TARGET_ARCH := -march=native
   endif
 
-  CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=0.4.2" -D "JUCE_APP_VERSION_HEX=0x402" -I /usr/include -I /usr/include/freetype2 -I ~/SDKs/VST3\ SDK -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I JuceLibraryCode/
+  CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "NDEBUG=1" -D "JUCER_LINUX_MAKE_7346DA2A=1" -D "JUCE_APP_VERSION=0.4.2.1" -D "JUCE_APP_VERSION_HEX=0x40201" -I /usr/include -I /usr/include/freetype2 -I ~/SDKs/VST3\ SDK -I ../../JuceLibraryCode -I ../../JuceLibraryCode/modules -I JuceLibraryCode/
   CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -O3 -rdynamic -fvisibility=hidden
   CXXFLAGS += $(CFLAGS) -std=c++11
-  LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -fvisibility=hidden -L/usr/X11R6/lib/ -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -ldl -lXext -lGLU -rdynamic -fPIC
+  LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -fvisibility=hidden -L/usr/X11R6/lib/ -lGL -lX11 -lXext -lXinerama -lasound -ldl -lfreetype -lpthread -lrt -ldl -lXext -lGLU -rdynamic -fPIC -Wl,-rpath,'$$ORIGIN'
 
   TARGET := open-ephys-release
   BLDCMD = $(CXX) -o $(OUTDIR)/$(TARGET) $(OBJECTS) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH)
diff --git a/Builds/MacOSX/Info-App.plist b/Builds/MacOSX/Info-App.plist
index d6c7290d7f5f5fa579e83afc7e663d3ffbc1358d..29f12d9086cc1628e0c03fdeaf32d19f415fed47 100644
--- a/Builds/MacOSX/Info-App.plist
+++ b/Builds/MacOSX/Info-App.plist
@@ -18,9 +18,9 @@
     <key>CFBundleSignature</key>
     <string>????</string>
     <key>CFBundleShortVersionString</key>
-    <string>0.4.2</string>
+    <string>0.4.2.1</string>
     <key>CFBundleVersion</key>
-    <string>0.4.2</string>
+    <string>0.4.2.1</string>
     <key>NSHumanReadableCopyright</key>
     <string>Open Ephys</string>
     <key>NSHighResolutionCapable</key>
diff --git a/Builds/MacOSX/OpenEphys.xcworkspace/contents.xcworkspacedata b/Builds/MacOSX/OpenEphys.xcworkspace/contents.xcworkspacedata
index 0a9ef155f588a09c06f0262dbffa8d353a84a3a2..3a7b70872579064f8214d8a710b996952e8629c6 100644
--- a/Builds/MacOSX/OpenEphys.xcworkspace/contents.xcworkspacedata
+++ b/Builds/MacOSX/OpenEphys.xcworkspace/contents.xcworkspacedata
@@ -65,9 +65,6 @@
       <FileRef
          location = "group:SerialInput/SerialInput.xcodeproj">
       </FileRef>
-      <FileRef
-         location = "group:SpikeRaster/SpikeRaster.xcodeproj">
-      </FileRef>
       <FileRef
          location = "group:SpikeSorter/SpikeSorter.xcodeproj">
       </FileRef>
diff --git a/Builds/MacOSX/Plugins/NWBFormat/NWBFormat.xcodeproj/project.pbxproj b/Builds/MacOSX/Plugins/NWBFormat/NWBFormat.xcodeproj/project.pbxproj
index 4c60410d56661e3b3b1e64cce1b85f1d72d09936..921608e444f8a352d3b802313ca12245375d14a9 100644
--- a/Builds/MacOSX/Plugins/NWBFormat/NWBFormat.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/Plugins/NWBFormat/NWBFormat.xcodeproj/project.pbxproj
@@ -239,6 +239,7 @@
 				E1F91DEC1DBE670500FF13EA /* Release */,
 			);
 			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
 		};
 /* End XCConfigurationList section */
 	};
diff --git a/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj b/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj
index c7ec046745c24e7a999f8886f5951ad00c83c2d5..688922995b904eeaf72f3e8b721819ce474a81b3 100644
--- a/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj
@@ -3358,8 +3358,8 @@
 					"_DEBUG=1",
 					"DEBUG=1",
 					"JUCER_XCODE_MAC_F6D2F4CF=1",
-					"JUCE_APP_VERSION=0.4.2",
-					"JUCE_APP_VERSION_HEX=0x402", );
+					"JUCE_APP_VERSION=0.4.2.1",
+					"JUCE_APP_VERSION_HEX=0x40201", );
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				HEADER_SEARCH_PATHS = ("~/SDKs/vstsdk2.4", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "JuceLibraryCode/", "$(inherited)");
 				INFOPLIST_FILE = Info-App.plist;
@@ -3382,8 +3382,8 @@
 					"_NDEBUG=1",
 					"NDEBUG=1",
 					"JUCER_XCODE_MAC_F6D2F4CF=1",
-					"JUCE_APP_VERSION=0.4.2",
-					"JUCE_APP_VERSION_HEX=0x402", );
+					"JUCE_APP_VERSION=0.4.2.1",
+					"JUCE_APP_VERSION_HEX=0x40201", );
 				GCC_SYMBOLS_PRIVATE_EXTERN = YES;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				HEADER_SEARCH_PATHS = ("~/SDKs/vstsdk2.4", "../../JuceLibraryCode", "../../JuceLibraryCode/modules", "JuceLibraryCode/", "$(inherited)");
diff --git a/Builds/VisualStudio2012/open-ephys.vcxproj b/Builds/VisualStudio2012/open-ephys.vcxproj
index 4ca750dc9a351b7f3e778e67c666f874fa10fc3c..4ba7d96512184069544079c433247d9e6cac9fd0 100644
--- a/Builds/VisualStudio2012/open-ephys.vcxproj
+++ b/Builds/VisualStudio2012/open-ephys.vcxproj
@@ -85,7 +85,7 @@
       <Optimization>Disabled</Optimization>
       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
@@ -130,7 +130,7 @@
     <ClCompile>
       <Optimization>Full</Optimization>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
@@ -177,7 +177,7 @@
       <Optimization>Disabled</Optimization>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
@@ -220,7 +220,7 @@
     <ClCompile>
       <Optimization>Full</Optimization>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCER_VS2012_78A501F=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
diff --git a/Builds/VisualStudio2012/resources.rc b/Builds/VisualStudio2012/resources.rc
index 13bfc913a492ab1a9b507be55871002f2d99aaa7..8582bebd4f2d17cfd432bf1576b35c7ed7466274 100644
--- a/Builds/VisualStudio2012/resources.rc
+++ b/Builds/VisualStudio2012/resources.rc
@@ -7,7 +7,7 @@
 #include <windows.h>
 
 VS_VERSION_INFO VERSIONINFO
-FILEVERSION  0,4,2,0
+FILEVERSION  0,4,2,1
 BEGIN
   BLOCK "StringFileInfo"
   BEGIN
@@ -15,9 +15,9 @@ BEGIN
     BEGIN
       VALUE "CompanyName",  "Open Ephys\0"
       VALUE "FileDescription",  "open-ephys\0"
-      VALUE "FileVersion",  "0.4.2\0"
+      VALUE "FileVersion",  "0.4.2.1\0"
       VALUE "ProductName",  "open-ephys\0"
-      VALUE "ProductVersion",  "0.4.2\0"
+      VALUE "ProductVersion",  "0.4.2.1\0"
     END
   END
 
diff --git a/Builds/VisualStudio2013/Plugins/LFP_Viewer_Beta/LFP_Viewer_Beta.vcxproj b/Builds/VisualStudio2013/Plugins/LFP_Viewer_Beta/LFP_Viewer_Beta.vcxproj
index 59325ff17864cec8c4c06081d723f0304c261340..94a294e10b5401f0e6edd897a7d1f9cbd3fa704a 100644
--- a/Builds/VisualStudio2013/Plugins/LFP_Viewer_Beta/LFP_Viewer_Beta.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/LFP_Viewer_Beta/LFP_Viewer_Beta.vcxproj
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/Plugins/NetworkEvents/NetworkEvents.vcxproj b/Builds/VisualStudio2013/Plugins/NetworkEvents/NetworkEvents.vcxproj
index a1fb07bd496f0fa579a22857c4b40ea9cba95681..0f02f4cb78a89cc280c7211b8c7da950c3f46573 100644
--- a/Builds/VisualStudio2013/Plugins/NetworkEvents/NetworkEvents.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/NetworkEvents/NetworkEvents.vcxproj
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
       <PreprocessorDefinitions>ZEROMQ;OEPLUGIN;WIN32;_WINDOWS;DEBUG;_DEBUG;JUCE_API=__declspec(dllimport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.3.5;JUCE_APP_VERSION_HEX=0x305;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>../../../../Resources/windows-libs/ZeroMQ/include;..\..\..\..\JuceLibraryCode;..\..\..\..\JuceLibraryCode\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
@@ -103,7 +103,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
       <PreprocessorDefinitions>ZEROMQ;OEPLUGIN;WIN32;_WINDOWS;NDEBUG;JUCE_API=__declspec(dllimport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.3.5;JUCE_APP_VERSION_HEX=0x305;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>../../../../Resources/windows-libs/ZeroMQ/include;..\..\..\..\JuceLibraryCode;..\..\..\..\JuceLibraryCode\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
@@ -121,7 +121,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
       <PreprocessorDefinitions>ZEROMQ;OEPLUGIN;WIN32;_WINDOWS;NDEBUG;JUCE_API=__declspec(dllimport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.3.5;JUCE_APP_VERSION_HEX=0x305;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <AdditionalIncludeDirectories>../../../../Resources/windows-libs/ZeroMQ/include;..\..\..\..\JuceLibraryCode;..\..\..\..\JuceLibraryCode\modules;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
diff --git a/Builds/VisualStudio2013/Plugins/Phase Detector/Phase Detector.vcxproj b/Builds/VisualStudio2013/Plugins/Phase Detector/Phase Detector.vcxproj
index 44484ebcdba2a4fc8f1378b538c42b51be40ba24..a2f4d733c8be16cccbcc5e3872bf1ba061299f5f 100644
--- a/Builds/VisualStudio2013/Plugins/Phase Detector/Phase Detector.vcxproj	
+++ b/Builds/VisualStudio2013/Plugins/Phase Detector/Phase Detector.vcxproj	
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/Plugins/Plugins.sln b/Builds/VisualStudio2013/Plugins/Plugins.sln
index c167ab1547bbdd6e92c4273a2bcb87966002aad4..d03b5fb137a3d480b0afb7599674fc5bfa965bbb 100644
--- a/Builds/VisualStudio2013/Plugins/Plugins.sln
+++ b/Builds/VisualStudio2013/Plugins/Plugins.sln
@@ -40,14 +40,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpikeSorter", "SpikeSorter\
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExampleProcessor", "ExampleProcessor\ExampleProcessor.vcxproj", "{767D282E-0BE5-4B35-874A-3B1ED925F06B}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PCIeRhythm", "PCIeRhythm\PCIeRhythm.vcxproj", "{8F019559-89D4-4C33-BA0F-FF330C57BA2B}"
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BinaryWriter", "BinaryWriter\BinaryWriter.vcxproj", "{9DB31964-F7E8-49B0-92E9-BAB2C35AF4B5}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LFP_Viewer_Beta", "LFP_Viewer_Beta\LFP_Viewer_Beta.vcxproj", "{A6E2C4F0-63A3-496B-8929-1B2785FDBBFD}"
 EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SpikeRaster", "SpikeRaster\SpikeRaster.vcxproj", "{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}"
-EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NWBFormat", "NWBFormat\NWBFormat.vcxproj", "{270F2CBD-EE26-44CF-B53C-068CA80BFBF7}"
 	ProjectSection(ProjectDependencies) = postProject
 		{F250DB70-6E3E-408C-BD9E-1483D574499D} = {F250DB70-6E3E-408C-BD9E-1483D574499D}
@@ -261,18 +257,6 @@ Global
 		{767D282E-0BE5-4B35-874A-3B1ED925F06B}.Release|Mixed Platforms.ActiveCfg = Release|x64
 		{767D282E-0BE5-4B35-874A-3B1ED925F06B}.Release|Win32.ActiveCfg = Release|Win32
 		{767D282E-0BE5-4B35-874A-3B1ED925F06B}.Release|x64.ActiveCfg = Release|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Debug|Mixed Platforms.ActiveCfg = Release|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Debug|Mixed Platforms.Build.0 = Release|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Debug|Win32.ActiveCfg = Debug|Win32
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Debug|Win32.Build.0 = Debug|Win32
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Debug|x64.ActiveCfg = Debug|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Debug|x64.Build.0 = Debug|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Release|Mixed Platforms.ActiveCfg = Release|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Release|Mixed Platforms.Build.0 = Release|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Release|Win32.ActiveCfg = Release|Win32
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Release|Win32.Build.0 = Release|Win32
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Release|x64.ActiveCfg = Release|x64
-		{8F019559-89D4-4C33-BA0F-FF330C57BA2B}.Release|x64.Build.0 = Release|x64
 		{9DB31964-F7E8-49B0-92E9-BAB2C35AF4B5}.Debug|Mixed Platforms.ActiveCfg = Release|x64
 		{9DB31964-F7E8-49B0-92E9-BAB2C35AF4B5}.Debug|Mixed Platforms.Build.0 = Release|x64
 		{9DB31964-F7E8-49B0-92E9-BAB2C35AF4B5}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -297,18 +281,6 @@ Global
 		{A6E2C4F0-63A3-496B-8929-1B2785FDBBFD}.Release|Win32.Build.0 = Release|Win32
 		{A6E2C4F0-63A3-496B-8929-1B2785FDBBFD}.Release|x64.ActiveCfg = Release|x64
 		{A6E2C4F0-63A3-496B-8929-1B2785FDBBFD}.Release|x64.Build.0 = Release|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Debug|Mixed Platforms.ActiveCfg = Release|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Debug|Mixed Platforms.Build.0 = Release|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Debug|Win32.Build.0 = Debug|Win32
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Debug|x64.ActiveCfg = Debug|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Debug|x64.Build.0 = Debug|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Release|Mixed Platforms.ActiveCfg = Release|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Release|Mixed Platforms.Build.0 = Release|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Release|Win32.ActiveCfg = Release|Win32
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Release|Win32.Build.0 = Release|Win32
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Release|x64.ActiveCfg = Release|x64
-		{D6A842A4-AC32-4AD0-B6AF-01AF1FBC8661}.Release|x64.Build.0 = Release|x64
 		{270F2CBD-EE26-44CF-B53C-068CA80BFBF7}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
 		{270F2CBD-EE26-44CF-B53C-068CA80BFBF7}.Debug|Mixed Platforms.Build.0 = Debug|Win32
 		{270F2CBD-EE26-44CF-B53C-068CA80BFBF7}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -326,11 +298,13 @@ Global
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Debug|Win32.ActiveCfg = Debug|Win32
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Debug|Win32.Build.0 = Debug|Win32
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Debug|x64.ActiveCfg = Debug|x64
+		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Debug|x64.Build.0 = Debug|x64
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Release|Mixed Platforms.ActiveCfg = Release|Win32
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Release|Mixed Platforms.Build.0 = Release|Win32
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Release|Win32.ActiveCfg = Release|Win32
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Release|Win32.Build.0 = Release|Win32
 		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Release|x64.ActiveCfg = Release|x64
+		{F250DB70-6E3E-408C-BD9E-1483D574499D}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/Builds/VisualStudio2013/Plugins/PulsePalOutput/PulsePalOutput.vcxproj b/Builds/VisualStudio2013/Plugins/PulsePalOutput/PulsePalOutput.vcxproj
index 0e5433566f1ff70ad13d0aafd805105baddf743c..72936ceb095449c7c1a35226aebed6c5157a4a38 100644
--- a/Builds/VisualStudio2013/Plugins/PulsePalOutput/PulsePalOutput.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/PulsePalOutput/PulsePalOutput.vcxproj
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/Plugins/RecordControl/RecordControl.vcxproj b/Builds/VisualStudio2013/Plugins/RecordControl/RecordControl.vcxproj
index 52b6b4251f154a764a150294c971e8826b860369..20ee0e8df9acdacda7ed4727fdcb8d1217bd3394 100644
--- a/Builds/VisualStudio2013/Plugins/RecordControl/RecordControl.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/RecordControl/RecordControl.vcxproj
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/Plugins/Rectifier/Rectifier.vcxproj b/Builds/VisualStudio2013/Plugins/Rectifier/Rectifier.vcxproj
index 62ab80991460930f4b301cb1247c171719e4fa74..52407b0bc1243d425d53aa54eb3f79632eba1628 100644
--- a/Builds/VisualStudio2013/Plugins/Rectifier/Rectifier.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/Rectifier/Rectifier.vcxproj
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/Plugins/SerialInput/SerialInput.vcxproj b/Builds/VisualStudio2013/Plugins/SerialInput/SerialInput.vcxproj
index 9fcd277b7b269098b16cb8bbfe67efaad654eb67..b7bd2cc098f44920fcbf03493813e04f1396f174 100644
--- a/Builds/VisualStudio2013/Plugins/SerialInput/SerialInput.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/SerialInput/SerialInput.vcxproj
@@ -74,7 +74,7 @@
     <ClCompile>
       <WarningLevel>Level3</WarningLevel>
       <Optimization>Disabled</Optimization>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/Plugins/SpikeSorter/SpikeSorter.vcxproj b/Builds/VisualStudio2013/Plugins/SpikeSorter/SpikeSorter.vcxproj
index 693fe9028cfda94bc2ad2de74d098ab7a2c6c2d7..c6ec5249514f063577a441b2952cbb812de23d81 100644
--- a/Builds/VisualStudio2013/Plugins/SpikeSorter/SpikeSorter.vcxproj
+++ b/Builds/VisualStudio2013/Plugins/SpikeSorter/SpikeSorter.vcxproj
@@ -95,7 +95,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -109,7 +109,7 @@
       <Optimization>MaxSpeed</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
-      <SDLCheck>true</SDLCheck>
+      <SDLCheck>false</SDLCheck>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
diff --git a/Builds/VisualStudio2013/open-ephys.vcxproj b/Builds/VisualStudio2013/open-ephys.vcxproj
index 28b9e28dcbd726afc970f1f7173dd5ddcb9bfda6..611ed81bcb60c456cdc89b89e3073d634a3cedbd 100644
--- a/Builds/VisualStudio2013/open-ephys.vcxproj
+++ b/Builds/VisualStudio2013/open-ephys.vcxproj
@@ -85,7 +85,7 @@
       <Optimization>Disabled</Optimization>
       <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
@@ -131,7 +131,7 @@
     <ClCompile>
       <Optimization>Full</Optimization>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
@@ -179,7 +179,7 @@
       <Optimization>Disabled</Optimization>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
@@ -223,7 +223,7 @@
     <ClCompile>
       <Optimization>Full</Optimization>
       <AdditionalIncludeDirectories>~\SDKs\VST3 SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;JuceLibraryCode/;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2;JUCE_APP_VERSION_HEX=0x402;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;NOMINMAX;JUCE_API=__declspec(dllexport);JUCER_VS2013_78A5020=1;JUCE_APP_VERSION=0.4.2.1;JUCE_APP_VERSION_HEX=0x40201;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <RuntimeTypeInfo>true</RuntimeTypeInfo>
       <PrecompiledHeader/>
diff --git a/Builds/VisualStudio2013/resources.rc b/Builds/VisualStudio2013/resources.rc
index 13bfc913a492ab1a9b507be55871002f2d99aaa7..8582bebd4f2d17cfd432bf1576b35c7ed7466274 100644
--- a/Builds/VisualStudio2013/resources.rc
+++ b/Builds/VisualStudio2013/resources.rc
@@ -7,7 +7,7 @@
 #include <windows.h>
 
 VS_VERSION_INFO VERSIONINFO
-FILEVERSION  0,4,2,0
+FILEVERSION  0,4,2,1
 BEGIN
   BLOCK "StringFileInfo"
   BEGIN
@@ -15,9 +15,9 @@ BEGIN
     BEGIN
       VALUE "CompanyName",  "Open Ephys\0"
       VALUE "FileDescription",  "open-ephys\0"
-      VALUE "FileVersion",  "0.4.2\0"
+      VALUE "FileVersion",  "0.4.2.1\0"
       VALUE "ProductName",  "open-ephys\0"
-      VALUE "ProductVersion",  "0.4.2\0"
+      VALUE "ProductVersion",  "0.4.2.1\0"
     END
   END
 
diff --git a/JuceLibraryCode/JuceHeader.h b/JuceLibraryCode/JuceHeader.h
index 1cf20a1c5c7d43aeeabb48a43dc74f8f3c13823c..c0cf844233fd45f75d3b40fd499d4cc5e34b9217 100644
--- a/JuceLibraryCode/JuceHeader.h
+++ b/JuceLibraryCode/JuceHeader.h
@@ -42,8 +42,8 @@
 namespace ProjectInfo
 {
     const char* const  projectName    = "open-ephys";
-    const char* const  versionString  = "0.4.2";
-    const int          versionNumber  = 0x402;
+    const char* const  versionString  = "0.4.2.1";
+    const int          versionNumber  = 0x40201;
 }
 #endif
 
diff --git a/Projucer/Builds/LinuxMakefile/Makefile b/Projucer/Builds/LinuxMakefile/Makefile
index f6368828ac1fed29c4f46eade60fd3eb665a6fb9..f94c27832ed819ec3ad6299d061cf5211c828637 100644
--- a/Projucer/Builds/LinuxMakefile/Makefile
+++ b/Projucer/Builds/LinuxMakefile/Makefile
@@ -18,7 +18,7 @@ ifeq ($(CONFIG),Debug)
     TARGET_ARCH := -march=native
   endif
 
-  CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_6D53C8B4=1" -D "JUCE_APP_VERSION=4.2.1" -D "JUCE_APP_VERSION_HEX=0x40201" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../../JuceLibraryCode/modules
+  CPPFLAGS := $(DEPFLAGS) -D "LINUX=1" -D "DEBUG=1" -D "_DEBUG=1" -D "JUCER_LINUX_MAKE_6D53C8B4=1" -D "JUCE_APP_VERSION=4.2.1" -D "JUCE_APP_VERSION_HEX=0x40201" -D "JUCE_DISABLE_NATIVE_FILECHOOSERS=1" -I /usr/include -I /usr/include/freetype2 -I ../../JuceLibraryCode -I ../../../JuceLibraryCode/modules
   CFLAGS += $(CPPFLAGS) $(TARGET_ARCH) -g -ggdb -O0 -std=c++11
   CXXFLAGS += $(CFLAGS) -std=c++11
   LDFLAGS += $(TARGET_ARCH) -L$(BINDIR) -L$(LIBDIR) -L/usr/X11R6/lib/ -lX11 -lXext -lXinerama -ldl -lfreetype -lpthread -lrt -lcurl 
diff --git a/Resources/Scripts/install_linux_dependencies.sh b/Resources/Scripts/install_linux_dependencies.sh
index 070b596ddd11f0cbe1d421745b862ce7f08bee89..8b8c1c21a4b9f835640f3d0f6aa234f17bd9a61a 100755
--- a/Resources/Scripts/install_linux_dependencies.sh
+++ b/Resources/Scripts/install_linux_dependencies.sh
@@ -1,8 +1,12 @@
 #!/bin/bash
 
+# This script installs required packages using apt-get
+# It must be run with sudo. Example:
+# sudo bash install_linux_dependencies.sh
+
 # install g++
 apt-get -y install build-essential
 
 # install Juce dependencies
-apt-get -y install freeglut3-dev libfreetype6-dev libxinerama-dev libxcursor-dev libasound2-dev
+apt-get -y install freeglut3-dev libfreetype6-dev libxinerama-dev libxcursor-dev libasound2-dev libxrandr-dev
 
diff --git a/Source/Plugins/BinaryWriter/BinaryRecording.cpp b/Source/Plugins/BinaryWriter/BinaryRecording.cpp
index 986e90e72f9e5a4c145bc1efe1cf42f2b7ba4a69..9542f84937c0176e1d19b3e099fdfa19f8cb0c6d 100644
--- a/Source/Plugins/BinaryWriter/BinaryRecording.cpp
+++ b/Source/Plugins/BinaryWriter/BinaryRecording.cpp
@@ -49,13 +49,52 @@ void BinaryRecording::openFiles(File rootFolder, int experimentNumber, int recor
 	//Open channel files
 	int nProcessors = getNumRecordedProcessors();
 
-	for (int i = 0; i < nProcessors; i++)
+	m_channelIndexes.insertMultiple(0, 0, getNumRecordedChannels());
+	m_fileIndexes.insertMultiple(0, 0, getNumRecordedChannels());
+
+	int lastId = 0;
+	for (int proc = 0; proc < nProcessors; proc++)
 	{
-		const RecordProcessorInfo& pInfo = getProcessorInfo(i);
-		File datFile(basepath + "_" + String(pInfo.processorId) + "_" + String(recordingNumber) + ".dat");
-		ScopedPointer<SequentialBlockFile> bFile = new SequentialBlockFile(pInfo.recordedChannels.size(), samplesPerBlock);
-		if (bFile->openFile(datFile))
-			m_DataFiles.add(bFile.release());
+		const RecordProcessorInfo& pInfo = getProcessorInfo(proc);
+		int recChans = pInfo.recordedChannels.size();
+
+		for (int chan = 0; chan < recChans; chan++)
+		{
+			int recordedChan = pInfo.recordedChannels[chan];
+			int realChan = getRealChannel(recordedChan);
+			const DataChannel* channelInfo = getDataChannel(realChan);
+			int sourceId = channelInfo->getSourceNodeID();
+			int sourceSubIdx = channelInfo->getSubProcessorIdx();
+			int nInfoArrays = m_dataChannels.size();
+			bool found = false;
+			for (int i = lastId; i < nInfoArrays; i++)
+			{
+				if (sourceId == m_dataChannels.getReference(i)[0]->getSourceNodeID() && sourceSubIdx == m_dataChannels.getReference(i)[0]->getSubProcessorIdx())
+				{
+					m_channelIndexes.set(recordedChan, m_dataChannels.getReference(i).size());
+					m_fileIndexes.set(recordedChan, i);
+					m_dataChannels.getReference(i).add(getDataChannel(realChan));
+					found = true;
+					break;
+				}
+			}
+			if (!found)
+			{
+				File datFile(basepath + "_" + String(pInfo.processorId) + "_" + String(sourceId) + "." + String(sourceSubIdx) + "_" + String(recordingNumber) + ".dat");
+				ScopedPointer<SequentialBlockFile> bFile = new SequentialBlockFile(pInfo.recordedChannels.size(), samplesPerBlock);
+				if (bFile->openFile(datFile))
+					m_DataFiles.add(bFile.release());
+				else
+					m_DataFiles.add(nullptr);
+
+				ContinuousGroup newGroup;
+				newGroup.add(getDataChannel(realChan));
+				m_dataChannels.add(newGroup);
+				m_fileIndexes.set(recordedChan, nInfoArrays);
+				m_channelIndexes.set(recordedChan, 0);
+				
+			}
+		}
 	}
 	int nChans = getNumRecordedChannels();
 	//Origin Timestamp
@@ -130,7 +169,7 @@ void BinaryRecording::writeData(int writeChannel, int realChannel, const float*
 	FloatVectorOperations::copyWithMultiply(m_scaledBuffer.getData(), buffer, multFactor, size);
 	AudioDataConverters::convertFloatToInt16LE(m_scaledBuffer.getData(), m_intBuffer.getData(), size);
 
-	m_DataFiles[getProcessorFromChannel(writeChannel)]->writeChannel(getTimestamp(writeChannel)-m_startTS[writeChannel],getChannelNumInProc(writeChannel),m_intBuffer.getData(),size);
+	m_DataFiles[m_fileIndexes[writeChannel]]->writeChannel(getTimestamp(writeChannel)-m_startTS[writeChannel],m_channelIndexes[writeChannel],m_intBuffer.getData(),size);
 }
 
 //Code below is copied from OriginalRecording, so it's not as clean as newer one
diff --git a/Source/Plugins/BinaryWriter/BinaryRecording.h b/Source/Plugins/BinaryWriter/BinaryRecording.h
index a92f2acd429f274a370618dacce59d75dfe73697..d710dd4dfa9bd8334c2a2e89b3d709694df93a66 100644
--- a/Source/Plugins/BinaryWriter/BinaryRecording.h
+++ b/Source/Plugins/BinaryWriter/BinaryRecording.h
@@ -56,7 +56,7 @@ namespace BinaryRecordingEngine
 		static RecordEngineManager* getEngineManager();
 
 	private:
-
+		typedef Array<const DataChannel*> ContinuousGroup;
 		void openSpikeFile(String basepath, int spikeIndex, int recordingNumber);
 		String generateSpikeHeader(const SpikeChannel* elec);
 		String generateEventHeader();
@@ -71,6 +71,9 @@ namespace BinaryRecordingEngine
 		int m_bufferSize;
 
 		OwnedArray<SequentialBlockFile>  m_DataFiles;
+		Array<unsigned int> m_channelIndexes;
+		Array<unsigned int> m_fileIndexes;
+		Array<ContinuousGroup> m_dataChannels;
 
 		FILE* eventFile;
 		FILE* messageFile;
diff --git a/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.cpp b/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.cpp
index bed007fa9132ff7e5f7d66dcafd8da025bb0a3e2..fc3b8a080e95945f1854806734a5b06a8e692ac3 100644
--- a/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.cpp
+++ b/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.cpp
@@ -111,13 +111,13 @@ void HDF5FileBase::close()
     opened = false;
 }
 
-int HDF5FileBase::setAttribute(DataTypes type, const void* data, String path, String name)
+int HDF5FileBase::setAttribute(BaseDataType type, const void* data, String path, String name)
 {
     return setAttributeArray(type, data, 1, path, name);
 }
 
 
-int HDF5FileBase::setAttributeArray(DataTypes type, const void* data, int size, String path, String name)
+int HDF5FileBase::setAttributeArray(BaseDataType type, const void* data, int size, String path, String name)
 {
     H5Location* loc;
     Group gloc;
@@ -335,13 +335,13 @@ HDF5RecordingData* HDF5FileBase::getDataSet(String path)
     }
 }
 
-HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int chunkX, String path)
+HDF5RecordingData* HDF5FileBase::createDataSet(BaseDataType type, int sizeX, int chunkX, String path)
 {
     int chunks[3] = {chunkX, 0, 0};
     return createDataSet(type,1,&sizeX,chunks,path);
 }
 
-HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int sizeY, int chunkX, String path)
+HDF5RecordingData* HDF5FileBase::createDataSet(BaseDataType type, int sizeX, int sizeY, int chunkX, String path)
 {
     int size[2];
     int chunks[3] = {chunkX, 0, 0};
@@ -350,7 +350,7 @@ HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int si
     return createDataSet(type,2,size,chunks,path);
 }
 
-HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int sizeY, int sizeZ, int chunkX, String path)
+HDF5RecordingData* HDF5FileBase::createDataSet(BaseDataType type, int sizeX, int sizeY, int sizeZ, int chunkX, String path)
 {
     int size[3];
     int chunks[3] = {chunkX, 0, 0};
@@ -360,7 +360,7 @@ HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int si
     return createDataSet(type,3,size,chunks,path);
 }
 
-HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int sizeY, int sizeZ, int chunkX, int chunkY, String path)
+HDF5RecordingData* HDF5FileBase::createDataSet(BaseDataType type, int sizeX, int sizeY, int sizeZ, int chunkX, int chunkY, String path)
 {
     int size[3];
     int chunks[3] = {chunkX, chunkY, 0};
@@ -370,7 +370,7 @@ HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int sizeX, int si
     return createDataSet(type,3,size,chunks,path);
 }
 
-HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int dimension, int* size, int* chunking, String path)
+HDF5RecordingData* HDF5FileBase::createDataSet(BaseDataType type, int dimension, int* size, int* chunking, String path)
 {
     ScopedPointer<DataSet> data;
     DSetCreatPropList prop;
@@ -426,88 +426,135 @@ HDF5RecordingData* HDF5FileBase::createDataSet(DataTypes type, int dimension, in
 
 }
 
-H5::DataType HDF5FileBase::getNativeType(DataTypes type)
+H5::DataType HDF5FileBase::getNativeType(BaseDataType type)
 {
-    switch (type)
-    {
-        case I8:
-            return PredType::NATIVE_INT8;
-            break;
-        case I16:
-            return PredType::NATIVE_INT16;
-            break;
-        case I32:
-            return PredType::NATIVE_INT32;
-            break;
-        case I64:
-            return PredType::NATIVE_INT64;
-            break;
-        case U8:
-            return PredType::NATIVE_UINT8;
-            break;
-        case U16:
-            return PredType::NATIVE_UINT16;
-            break;
-        case U32:
-            return PredType::NATIVE_UINT32;
-            break;
-        case U64:
-            return PredType::NATIVE_UINT64;
-            break;
-        case F32:
-            return PredType::NATIVE_FLOAT;
-            break;
-		case F64:
-			return PredType::NATIVE_DOUBLE;
-			break;
-        case STR:
-            return StrType(PredType::C_S1,MAX_STR_SIZE);
-            break;
-    }
-    return PredType::NATIVE_INT32;
+	H5::DataType baseType;
+
+	switch (type.type)
+	{
+	case BaseDataType::Type::T_I8:
+		baseType = PredType::NATIVE_INT8;
+		break;
+	case BaseDataType::Type::T_I16:
+		baseType = PredType::NATIVE_INT16;
+		break;
+	case BaseDataType::Type::T_I32:
+		baseType = PredType::NATIVE_INT32;
+		break;
+	case BaseDataType::Type::T_I64:
+		baseType = PredType::NATIVE_INT64;
+		break;
+	case BaseDataType::Type::T_U8:
+		baseType = PredType::NATIVE_UINT8;
+		break;
+	case BaseDataType::Type::T_U16:
+		baseType = PredType::NATIVE_UINT16;
+		break;
+	case BaseDataType::Type::T_U32:
+		baseType = PredType::NATIVE_UINT32;
+		break;
+	case BaseDataType::Type::T_U64:
+		baseType = PredType::NATIVE_UINT64;
+		break;
+	case BaseDataType::Type::T_F32:
+		baseType = PredType::NATIVE_FLOAT;
+		break;
+	case BaseDataType::Type::T_F64:
+		baseType = PredType::NATIVE_DOUBLE;
+		break;
+	case BaseDataType::Type::T_STR:
+		return StrType(PredType::C_S1, type.typeSize);
+		break;
+	default:
+		baseType = PredType::NATIVE_INT32;
+	}
+	if (type.typeSize > 1)
+	{
+		hsize_t size = type.typeSize;
+		return ArrayType(baseType, 1, &size);
+	}
+	else return baseType;
 }
 
-H5::DataType HDF5FileBase::getH5Type(DataTypes type)
+H5::DataType HDF5FileBase::getH5Type(BaseDataType type)
 {
-    switch (type)
-    {
-        case I8:
-            return PredType::STD_I8LE;
-            break;
-        case I16:
-            return PredType::STD_I16LE;
-            break;
-        case I32:
-            return PredType::STD_I32LE;
-            break;
-        case I64:
-            return PredType::STD_I64LE;
-            break;
-        case U8:
-            return PredType::STD_U8LE;
-            break;
-        case U16:
-            return PredType::STD_U16LE;
-            break;
-        case U32:
-            return PredType::STD_U32LE;
-            break;
-        case U64:
-            return PredType::STD_U64LE;
-            break;
-        case F32:
-            return PredType::IEEE_F32LE;
-            break;
-		case F64:
-			return PredType::IEEE_F64LE;
-			break;
-        case STR:
-            return StrType(PredType::C_S1,MAX_STR_SIZE);
-            break;
-    }
-    return PredType::STD_I32LE;
+	H5::DataType baseType;
+
+	switch (type.type)
+	{
+	case BaseDataType::Type::T_I8:
+		baseType = PredType::STD_I8LE;
+		break;
+	case BaseDataType::Type::T_I16:
+		baseType = PredType::STD_I16LE;
+		break;
+	case BaseDataType::Type::T_I32:
+		baseType = PredType::STD_I32LE;
+		break;
+	case BaseDataType::Type::T_I64:
+		baseType = PredType::STD_I64LE;
+		break;
+	case BaseDataType::Type::T_U8:
+		baseType = PredType::STD_U8LE;
+		break;
+	case BaseDataType::Type::T_U16:
+		baseType = PredType::STD_U16LE;
+		break;
+	case BaseDataType::Type::T_U32:
+		baseType = PredType::STD_U32LE;
+		break;
+	case BaseDataType::Type::T_U64:
+		baseType = PredType::STD_U64LE;
+		break;
+	case BaseDataType::Type::T_F32:
+		return PredType::IEEE_F32LE;
+		break;
+	case BaseDataType::Type::T_F64:
+		baseType = PredType::IEEE_F64LE;
+		break;
+	case BaseDataType::Type::T_STR:
+		return StrType(PredType::C_S1, type.typeSize);
+		break;
+	default:
+		return PredType::STD_I32LE;
+	}
+	if (type.typeSize > 1)
+	{
+		hsize_t size = type.typeSize;
+		return ArrayType(baseType, 1, &size);
+	}
+	else return baseType;
 }
 
+//BaseDataType
+
+HDF5FileBase::BaseDataType::BaseDataType(HDF5FileBase::BaseDataType::Type t, size_t s)
+	: type(t), typeSize(s)
+{}
+
+HDF5FileBase::BaseDataType::BaseDataType()
+	: type(T_I32), typeSize(1)
+{}
+
+HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::STR(size_t size)
+{
+	return HDF5FileBase::BaseDataType(T_STR, size);
+}
+
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::U8 = HDF5FileBase::BaseDataType(T_U8, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::U16 = HDF5FileBase::BaseDataType(T_U16, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::U32 = HDF5FileBase::BaseDataType(T_U32, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::U64 = HDF5FileBase::BaseDataType(T_U64, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::I8 = HDF5FileBase::BaseDataType(T_I8, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::I16 = HDF5FileBase::BaseDataType(T_I16, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::I32 = HDF5FileBase::BaseDataType(T_I32, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::I64 = HDF5FileBase::BaseDataType(T_I64, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::F32 = HDF5FileBase::BaseDataType(T_F32, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::F64 = HDF5FileBase::BaseDataType(T_F64, 1);
+const HDF5FileBase::BaseDataType HDF5FileBase::BaseDataType::DSTR = HDF5FileBase::BaseDataType(T_STR, DEFAULT_STR_SIZE);
+
+//H5RecordingData
+
 HDF5RecordingData::HDF5RecordingData(DataSet* data)
 {
     DataSpace dSpace;
@@ -543,12 +590,12 @@ HDF5RecordingData::~HDF5RecordingData()
 	//Safety
 	dSet->flush(H5F_SCOPE_GLOBAL);
 }
-int HDF5RecordingData::writeDataBlock(int xDataSize, HDF5FileBase::DataTypes type, const void* data)
+int HDF5RecordingData::writeDataBlock(int xDataSize, HDF5FileBase::BaseDataType type, const void* data)
 {
     return writeDataBlock(xDataSize,size[1],type,data);
 }
 
-int HDF5RecordingData::writeDataBlock(int xDataSize, int yDataSize, HDF5FileBase::DataTypes type, const void* data)
+int HDF5RecordingData::writeDataBlock(int xDataSize, int yDataSize, HDF5FileBase::BaseDataType type, const void* data)
 {
     hsize_t dim[3],offset[3];
     DataSpace fSpace;
@@ -602,7 +649,7 @@ int HDF5RecordingData::writeDataBlock(int xDataSize, int yDataSize, HDF5FileBase
 }
 
 
-int HDF5RecordingData::writeDataRow(int yPos, int xDataSize, HDF5FileBase::DataTypes type, const void* data)
+int HDF5RecordingData::writeDataRow(int yPos, int xDataSize, HDF5FileBase::BaseDataType type, const void* data)
 {
     hsize_t dim[2],offset[2];
     DataSpace fSpace;
diff --git a/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.h b/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.h
index 7f0796bd5d75c5b7e718450daf95ca88fca59288..9f0aac6758a91129927b26231d4918a0667e6345 100644
--- a/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.h
+++ b/Source/Plugins/CommonLibs/OpenEphysHDF5Lib/HDF5FileFormat.h
@@ -27,13 +27,13 @@
 #include <CommonLibHeader.h>
 
 #define PROCESS_ERROR std::cerr << error.getCDetailMsg() << std::endl; return -1
-#define CHECK_ERROR(x) if (x) std::cerr << "Error at HDFRecording " << __LINE__ << std::endl;
+#define CHECK_ERROR(x) if (x) std::cerr << "Error at " << __FILE__ " " << __LINE__ << std::endl;
 
 #ifndef CHUNK_XSIZE
 #define CHUNK_XSIZE 2048
 #endif
 
-#define MAX_STR_SIZE 256
+#define DEFAULT_STR_SIZE 256
 
 namespace H5
 {
@@ -59,18 +59,39 @@ public:
     virtual String getFileName() = 0;
     bool isOpen() const;
 	bool isReadyToOpen() const;
-    typedef enum DataTypes { U8, U16, U32, U64, I8, I16, I32, I64, F32, F64, STR} DataTypes;
-
-    static H5::DataType getNativeType(DataTypes type);
-    static H5::DataType getH5Type(DataTypes type);
+	class COMMON_LIB BaseDataType {
+	public:
+		enum Type { T_U8, T_U16, T_U32, T_U64, T_I8, T_I16, T_I32, T_I64, T_F32, T_F64, T_STR };
+		BaseDataType();
+		BaseDataType(Type, size_t);
+		Type type;
+		size_t typeSize;
+
+		//handy accessors
+		static const BaseDataType U8;
+		static const BaseDataType U16;
+		static const BaseDataType U32;
+		static const BaseDataType U64;
+		static const BaseDataType I8;
+		static const BaseDataType I16;
+		static const BaseDataType I32;
+		static const BaseDataType I64;
+		static const BaseDataType F32;
+		static const BaseDataType F64;
+		static const BaseDataType DSTR;
+		static BaseDataType STR(size_t size);
+	};
+
+	static H5::DataType getNativeType(BaseDataType type);
+	static H5::DataType getH5Type(BaseDataType type);
 
 protected:
 
     virtual int createFileStructure() = 0;
 
-    int setAttribute(DataTypes type, const void* data, String path, String name);
+	int setAttribute(BaseDataType type, const void* data, String path, String name);
     int setAttributeStr(const String& value, String path, String name);
-    int setAttributeArray(DataTypes type, const void* data, int size, String path, String name);
+	int setAttributeArray(BaseDataType type, const void* data, int size, String path, String name);
 	int setAttributeStrArray(const StringArray& data, String path, String name);
     int createGroup(String path);
 	int createGroupIfDoesNotExist(String path);
@@ -78,10 +99,10 @@ protected:
     HDF5RecordingData* getDataSet(String path);
 
     //aliases for createDataSet
-    HDF5RecordingData* createDataSet(DataTypes type, int sizeX, int chunkX, String path);
-    HDF5RecordingData* createDataSet(DataTypes type, int sizeX, int sizeY, int chunkX, String path);
-    HDF5RecordingData* createDataSet(DataTypes type, int sizeX, int sizeY, int sizeZ, int chunkX, String path);
-    HDF5RecordingData* createDataSet(DataTypes type, int sizeX, int sizeY, int sizeZ, int chunkX, int chunkY, String path);
+	HDF5RecordingData* createDataSet(BaseDataType type, int sizeX, int chunkX, String path);
+	HDF5RecordingData* createDataSet(BaseDataType type, int sizeX, int sizeY, int chunkX, String path);
+	HDF5RecordingData* createDataSet(BaseDataType type, int sizeX, int sizeY, int sizeZ, int chunkX, String path);
+	HDF5RecordingData* createDataSet(BaseDataType type, int sizeX, int sizeY, int sizeZ, int chunkX, int chunkY, String path);
 
     bool readyToOpen;
 
@@ -89,7 +110,7 @@ private:
 	int setAttributeStrArray(Array<const char*>& data, int maxSize, String path, String name);
 
     //create an extendable dataset
-    HDF5RecordingData* createDataSet(DataTypes type, int dimension, int* size, int* chunking, String path);
+	HDF5RecordingData* createDataSet(BaseDataType type, int dimension, int* size, int* chunking, String path);
     int open(bool newfile, int nChans);
     ScopedPointer<H5::H5File> file;
     bool opened;
@@ -103,10 +124,10 @@ public:
     HDF5RecordingData(H5::DataSet* data);
     ~HDF5RecordingData();
 
-    int writeDataBlock(int xDataSize, HDF5FileBase::DataTypes type, const void* data);
-    int writeDataBlock(int xDataSize, int yDataSize, HDF5FileBase::DataTypes type, const void* data);
+	int writeDataBlock(int xDataSize, HDF5FileBase::BaseDataType type, const void* data);
+	int writeDataBlock(int xDataSize, int yDataSize, HDF5FileBase::BaseDataType type, const void* data);
 
-    int writeDataRow(int yPos, int xDataSize, HDF5FileBase::DataTypes type, const void* data);
+	int writeDataRow(int yPos, int xDataSize, HDF5FileBase::BaseDataType type, const void* data);
 
     void getRowXPositions(Array<uint32>& rows);
 
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp b/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp
index 19d7f8f4b92e565640b8816ed4dff78122c9a77f..185f885ed155fa6782e13885ae8a2e58c0c1e34f 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp
+++ b/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp
@@ -281,8 +281,8 @@ void HDF5Recording::writeSpike(int electrodeIndex, const SpikeEvent* spike)
 void HDF5Recording::startAcquisition()
 {
     eventFile = new KWEFile();
-    eventFile->addEventType("TTL",HDF5FileBase::U8,"event_channels");
-    eventFile->addEventType("Messages",HDF5FileBase::STR,"Text");
+    eventFile->addEventType("TTL",HDF5FileBase::BaseDataType::U8,"event_channels");
+	eventFile->addEventType("Messages", HDF5FileBase::BaseDataType::DSTR, "Text");
     spikesFile = new KWXFile();
 }
 
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.cpp b/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.cpp
index 2bf8593d367e778fea0e048de2996f81b2a7cac8..110d86cf3c315347dab062f3ede100d28fe27206 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.cpp
+++ b/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.cpp
@@ -69,31 +69,31 @@ void KWDFile::startNewRecording(int recordingNumber, int nChannels, KWIKRecordin
     String recordPath = String("/recordings/")+String(recordingNumber);
     CHECK_ERROR(createGroup(recordPath));
     CHECK_ERROR(setAttributeStr(info->name,recordPath,String("name")));
-    CHECK_ERROR(setAttribute(U64,&(info->start_time),recordPath,String("start_time")));
-    CHECK_ERROR(setAttribute(U32,&(info->start_sample),recordPath,String("start_sample")));
-    CHECK_ERROR(setAttribute(F32,&(info->sample_rate),recordPath,String("sample_rate")));
-    CHECK_ERROR(setAttribute(U32,&(info->bit_depth),recordPath,String("bit_depth")));
+	CHECK_ERROR(setAttribute(BaseDataType::U64, &(info->start_time), recordPath, String("start_time")));
+	CHECK_ERROR(setAttribute(BaseDataType::U32, &(info->start_sample), recordPath, String("start_sample")));
+	CHECK_ERROR(setAttribute(BaseDataType::F32, &(info->sample_rate), recordPath, String("sample_rate")));
+	CHECK_ERROR(setAttribute(BaseDataType::U32, &(info->bit_depth), recordPath, String("bit_depth")));
     CHECK_ERROR(createGroup(recordPath+"/application_data"));
    // CHECK_ERROR(setAttributeArray(F32,info->bitVolts.getRawDataPointer(),info->bitVolts.size(),recordPath+"/application_data",String("channel_bit_volts")));
-	bitVoltsSet = createDataSet(F32, info->bitVolts.size(), 0, recordPath + "/application_data/channel_bit_volts");
+	bitVoltsSet = createDataSet(BaseDataType::F32, info->bitVolts.size(), 0, recordPath + "/application_data/channel_bit_volts");
 	if (bitVoltsSet.get())
-		bitVoltsSet->writeDataBlock(info->bitVolts.size(), F32, info->bitVolts.getRawDataPointer());
+		bitVoltsSet->writeDataBlock(info->bitVolts.size(), BaseDataType::F32, info->bitVolts.getRawDataPointer());
 	else
 		std::cerr << "Error creating bitvolts data set" << std::endl;
 	
-    CHECK_ERROR(setAttribute(U8,&mSample,recordPath+"/application_data",String("is_multiSampleRate_data")));
+	CHECK_ERROR(setAttribute(BaseDataType::U8, &mSample, recordPath + "/application_data", String("is_multiSampleRate_data")));
     //CHECK_ERROR(setAttributeArray(F32,info->channelSampleRates.getRawDataPointer(),info->channelSampleRates.size(),recordPath+"/application_data",String("channel_sample_rates")));
-	sampleRateSet = createDataSet(F32, info->channelSampleRates.size(), 0, recordPath + "/application_data/channel_sample_rates");
+	sampleRateSet = createDataSet(BaseDataType::F32, info->channelSampleRates.size(), 0, recordPath + "/application_data/channel_sample_rates");
 	if (sampleRateSet.get())
-		sampleRateSet->writeDataBlock(info->channelSampleRates.size(), F32, info->channelSampleRates.getRawDataPointer());
+		sampleRateSet->writeDataBlock(info->channelSampleRates.size(), BaseDataType::F32, info->channelSampleRates.getRawDataPointer());
 	else
 		std::cerr << "Error creating sample rates data set" << std::endl;
 
-    recdata = createDataSet(I16,0,nChannels,CHUNK_XSIZE,recordPath+"/data");
+	recdata = createDataSet(BaseDataType::I16, 0, nChannels, CHUNK_XSIZE, recordPath + "/data");
     if (!recdata.get())
         std::cerr << "Error creating data set" << std::endl;
 
-	tsData = createDataSet(I64, 0, nChannels, TIMESTAMP_CHUNK_SIZE, recordPath + "/application_data/timestamps");
+	tsData = createDataSet(BaseDataType::I64, 0, nChannels, TIMESTAMP_CHUNK_SIZE, recordPath + "/application_data/timestamps");
 	if (!tsData.get())
 		std::cerr << "Error creating timestamps data set" << std::endl;
 
@@ -106,7 +106,7 @@ void KWDFile::stopRecording()
     String path = String("/recordings/")+String(recordingNumber)+String("/data");
     recdata->getRowXPositions(samples);
 
-    CHECK_ERROR(setAttributeArray(U32,samples.getRawDataPointer(),samples.size(),path,"valid_samples"));
+	CHECK_ERROR(setAttributeArray(BaseDataType::U32, samples.getRawDataPointer(), samples.size(), path, "valid_samples"));
     //ScopedPointer does the deletion and destructors the closings
     recdata = nullptr;
 	tsData = nullptr;
@@ -116,13 +116,13 @@ int KWDFile::createFileStructure()
 {
     const uint16 ver = 2;
     if (createGroup("/recordings")) return -1;
-    if (setAttribute(U16,(void*)&ver,"/","kwik_version")) return -1;
+	if (setAttribute(BaseDataType::U16, (void*)&ver, "/", "kwik_version")) return -1;
     return 0;
 }
 
 void KWDFile::writeBlockData(int16* data, int nSamples)
 {
-    CHECK_ERROR(recdata->writeDataBlock(nSamples,I16,data));
+	CHECK_ERROR(recdata->writeDataBlock(nSamples, BaseDataType::I16, data));
 }
 
 void KWDFile::writeRowData(int16* data, int nSamples)
@@ -131,7 +131,7 @@ void KWDFile::writeRowData(int16* data, int nSamples)
     {
         curChan=0;
     }
-    CHECK_ERROR(recdata->writeDataRow(curChan,nSamples,I16,data));
+	CHECK_ERROR(recdata->writeDataRow(curChan, nSamples, BaseDataType::I16, data));
     curChan++;
 }
 
@@ -139,7 +139,7 @@ void KWDFile::writeRowData(int16* data, int nSamples, int channel)
 {
 	if (channel >= 0 && channel < nChannels)
 	{
-		CHECK_ERROR(recdata->writeDataRow(channel, nSamples, I16, data));
+		CHECK_ERROR(recdata->writeDataRow(channel, nSamples, BaseDataType::I16, data));
 		curChan = channel;
 	}
 }
@@ -148,7 +148,7 @@ void KWDFile::writeTimestamps(int64* ts, int nTs, int channel)
 {
 	if (channel >= 0 && channel < nChannels)
 	{
-		CHECK_ERROR(tsData->writeDataRow(channel, nTs, I64, ts));
+		CHECK_ERROR(tsData->writeDataRow(channel, nTs, BaseDataType::I64, ts));
 	}
 }
 
@@ -190,20 +190,21 @@ int KWEFile::createFileStructure()
         if (createGroup(path)) return -1;
         path += "/events";
         if (createGroup(path)) return -1;
-        dSet = createDataSet(U64,0,EVENT_CHUNK_SIZE,path + "/time_samples");
+		dSet = createDataSet(BaseDataType::U64, 0, EVENT_CHUNK_SIZE, path + "/time_samples");
         if (!dSet) return -1;
-        dSet = createDataSet(U16,0,EVENT_CHUNK_SIZE,path + "/recording");
+		dSet = createDataSet(BaseDataType::U16, 0, EVENT_CHUNK_SIZE, path + "/recording");
         if (!dSet) return -1;
         path += "/user_data";
         if (createGroup(path)) return -1;
-        dSet = createDataSet(U8,0,EVENT_CHUNK_SIZE,path + "/eventID");
+		dSet = createDataSet(BaseDataType::U8, 0, EVENT_CHUNK_SIZE, path + "/eventID");
         if (!dSet) return -1;
-        dSet = createDataSet(U8,0,EVENT_CHUNK_SIZE,path + "/nodeID");
+		dSet = createDataSet(BaseDataType::U8, 0, EVENT_CHUNK_SIZE, path + "/nodeID");
         if (!dSet) return -1;
         dSet = createDataSet(eventTypes[i],0,EVENT_CHUNK_SIZE,path + "/" + eventDataNames[i]);
         if (!dSet) return -1;
     }
-    if (setAttribute(U16,(void*)&ver,"/","kwik_version")) return -1;
+	if (setAttribute(BaseDataType::U16, (void*)&ver, "/", "kwik_version")) return -1;
+
     return 0;
 }
 
@@ -214,10 +215,10 @@ void KWEFile::startNewRecording(int recordingNumber, KWIKRecordingInfo* info)
     String recordPath = String("/recordings/")+String(recordingNumber);
     CHECK_ERROR(createGroup(recordPath));
     CHECK_ERROR(setAttributeStr(info->name,recordPath,String("name")));
-    CHECK_ERROR(setAttribute(U64,&(info->start_time),recordPath,String("start_time")));
+	CHECK_ERROR(setAttribute(BaseDataType::U64, &(info->start_time), recordPath, String("start_time")));
     //	CHECK_ERROR(setAttribute(U32,&(info->start_sample),recordPath,String("start_sample")));
-    CHECK_ERROR(setAttribute(F32,&(info->sample_rate),recordPath,String("sample_rate")));
-    CHECK_ERROR(setAttribute(U32,&(info->bit_depth),recordPath,String("bit_depth")));
+	CHECK_ERROR(setAttribute(BaseDataType::F32, &(info->sample_rate), recordPath, String("sample_rate")));
+	CHECK_ERROR(setAttribute(BaseDataType::U32, &(info->bit_depth), recordPath, String("bit_depth")));
    // CHECK_ERROR(createGroup(recordPath + "/raw"));
   //  CHECK_ERROR(createGroup(recordPath + "/raw/hdf5_paths"));
 
@@ -264,10 +265,10 @@ void KWEFile::writeEvent(int type, uint8 id, uint8 processor, void* data, int64
         std::cerr << "HDF5::writeEvent Invalid event type " << type << std::endl;
         return;
     }
-    CHECK_ERROR(timeStamps[type]->writeDataBlock(1,U64,&timestamp));
-    CHECK_ERROR(recordings[type]->writeDataBlock(1,I32,&recordingNumber));
-    CHECK_ERROR(eventID[type]->writeDataBlock(1,U8,&id));
-    CHECK_ERROR(nodeID[type]->writeDataBlock(1,U8,&processor));
+	CHECK_ERROR(timeStamps[type]->writeDataBlock(1, BaseDataType::U64, &timestamp));
+	CHECK_ERROR(recordings[type]->writeDataBlock(1, BaseDataType::I32, &recordingNumber));
+	CHECK_ERROR(eventID[type]->writeDataBlock(1, BaseDataType::U8, &id));
+	CHECK_ERROR(nodeID[type]->writeDataBlock(1, BaseDataType::U8, &processor));
     CHECK_ERROR(eventData[type]->writeDataBlock(1,eventTypes[type],data));
 }
 
@@ -283,7 +284,7 @@ void KWEFile::writeEvent(int type, uint8 id, uint8 processor, void* data, int64
     kwdIndex++;
 }*/
 
-void KWEFile::addEventType(String name, DataTypes type, String dataName)
+void KWEFile::addEventType(String name, BaseDataType type, String dataName)
 {
     eventNames.add(name);
     eventTypes.add(type);
@@ -325,7 +326,7 @@ int KWXFile::createFileStructure()
 {
     const uint16 ver = 2;
     if (createGroup("/channel_groups")) return -1;
-    if (setAttribute(U16,(void*)&ver,"/","kwik_version")) return -1;
+	if (setAttribute(BaseDataType::U16, (void*)&ver, "/", "kwik_version")) return -1;
     for (int i=0; i < channelArray.size(); i++)
     {
         int res = createChannelGroup(i);
@@ -346,11 +347,11 @@ int KWXFile::createChannelGroup(int index)
     int nChannels = channelArray[index];
     String path("/channel_groups/"+String(index));
     CHECK_ERROR(createGroup(path));
-    dSet = createDataSet(I16,0,0,nChannels,SPIKE_CHUNK_XSIZE,SPIKE_CHUNK_YSIZE,path+"/waveforms_filtered");
+	dSet = createDataSet(BaseDataType::I16, 0, 0, nChannels, SPIKE_CHUNK_XSIZE, SPIKE_CHUNK_YSIZE, path + "/waveforms_filtered");
     if (!dSet) return -1;
-    dSet = createDataSet(U64,0,SPIKE_CHUNK_XSIZE,path+"/time_samples");
+	dSet = createDataSet(BaseDataType::U64, 0, SPIKE_CHUNK_XSIZE, path + "/time_samples");
     if (!dSet) return -1;
-    dSet = createDataSet(U16,0,SPIKE_CHUNK_XSIZE,path+"/recordings");
+	dSet = createDataSet(BaseDataType::U16, 0, SPIKE_CHUNK_XSIZE, path + "/recordings");
     if (!dSet) return -1;
     return 0;
 }
@@ -412,7 +413,7 @@ void KWXFile::writeSpike(int groupIndex, int nSamples, const float* data, Array<
         }
     }
 
-    CHECK_ERROR(spikeArray[groupIndex]->writeDataBlock(1,nSamples,I16,transformVector));
-    CHECK_ERROR(recordingArray[groupIndex]->writeDataBlock(1,I32,&recordingNumber));
-    CHECK_ERROR(timeStamps[groupIndex]->writeDataBlock(1,U64,&timestamp));
+	CHECK_ERROR(spikeArray[groupIndex]->writeDataBlock(1, nSamples, BaseDataType::I16, transformVector));
+	CHECK_ERROR(recordingArray[groupIndex]->writeDataBlock(1, BaseDataType::I32, &recordingNumber));
+	CHECK_ERROR(timeStamps[groupIndex]->writeDataBlock(1, BaseDataType::U64, &timestamp));
 }
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.h b/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.h
index 5a467b68f7f4ef7b3278b90fd90246d18392e767..0ffefea2d0ca8ad945af942c4b69b7f704b24423 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.h
+++ b/Source/Plugins/KWIKFormat/RecordEngine/KWIKFormat.h
@@ -80,7 +80,7 @@ public:
     void stopRecording();
     void writeEvent(int type, uint8 id, uint8 processor, void* data, int64 timestamp);
   //  void addKwdFile(String filename);
-    void addEventType(String name, DataTypes type, String dataName);
+	void addEventType(String name, BaseDataType type, String dataName);
     String getFileName();
 
 protected:
@@ -95,7 +95,7 @@ private:
     OwnedArray<HDF5RecordingData> nodeID;
     OwnedArray<HDF5RecordingData> eventData;
     Array<String> eventNames;
-    Array<DataTypes> eventTypes;
+	Array<BaseDataType> eventTypes;
     Array<String> eventDataNames;
     int kwdIndex;
 
diff --git a/Source/Plugins/NWBFormat/NWBFormat.cpp b/Source/Plugins/NWBFormat/NWBFormat.cpp
index 4288c4dddd82ef1b5f8c87ff1180c4327cd92562..dea14b24618a0741263cbb04c9b022a32884f58b 100644
--- a/Source/Plugins/NWBFormat/NWBFormat.cpp
+++ b/Source/Plugins/NWBFormat/NWBFormat.cpp
@@ -36,10 +36,16 @@
 #define SPIKE_CHUNK_YSIZE 40
 #endif
 
+ #define MAX_BUFFER_SIZE 40960
+
  NWBFile::NWBFile(String fName, String ver, String idText) : HDF5FileBase(), filename(fName), identifierText(idText), GUIVersion(ver)
  {
 	 //Init stuff
 	 readyToOpen=true; //In KWIK this is in initFile, but the new recordEngine methods make it safe for it to be here
+
+	 scaledBuffer.malloc(MAX_BUFFER_SIZE);
+	 intBuffer.malloc(MAX_BUFFER_SIZE);
+	 bufferSize = MAX_BUFFER_SIZE;
  }
  
  NWBFile::~NWBFile()
@@ -65,10 +71,7 @@ int NWBFile::createFileStructure()
 	if (createGroup("/stimulus")) return -1;
 
 	if (createGroup("/acquisition/timeseries")) return -1;
-	if (createGroup("/acquisition/timeseries/continuous")) return -1;
-	if (createGroup("/acquisition/timeseries/spikes")) return -1;
-	if (createGroup("/acquisition/timeseries/messages")) return -1;
-	if (createGroup("/acquisition/timeseries/events")) return -1;
+
 
 	if (createGroup("/general/data_collection")) return -1;
 
@@ -87,167 +90,279 @@ int NWBFile::createFileStructure()
 	return 0;
 }
  
- bool NWBFile::startNewRecording(int recordingNumber, const Array<NWBRecordingInfo>& continuousInfo, const Array<NWBRecordingInfo>& spikeInfo)
+bool NWBFile::startNewRecording(int recordingNumber, const Array<ContinuousGroup>& continuousArray,
+	const Array<const EventChannel*>& eventArray, const Array<const SpikeChannel*>& electrodeArray)
  {
 	 //Created each time a new recording is started. Creates the specific file structures and attributes
 	 //for that specific recording
-	 HDF5RecordingData* dSet;
 	 String basePath;
-	 int nCont = continuousInfo.size();
+	 StringArray ancestry;
+	 String rootPath = "/acquisition/timeseries/recording" + String(recordingNumber);
+	 if (createGroup(rootPath)) return false;
+	 if (createGroupIfDoesNotExist(rootPath + "/continuous")) return false;
+	 if (createGroupIfDoesNotExist(rootPath + "/spikes")) return false;
+	 if (createGroupIfDoesNotExist(rootPath + "/events")) return false;
+
+	 //just in case
+	 continuousDataSets.clearQuick(true);
+	 spikeDataSets.clearQuick(true);
+	 eventDataSets.clearQuick(true);
+
+	 ScopedPointer<TimeSeries> tsStruct;
+	 ScopedPointer<HDF5RecordingData> dSet;
+
+	 int nCont;
+	 nCont = continuousArray.size();
 	 for (int i = 0; i < nCont; i++)
 	 {
-		 basePath = "/acquisition/timeseries/continuous";
-		 basePath = basePath + "/processor" + String(continuousInfo[i].processorId) + "_" + String(continuousInfo[i].sourceId) + "." + String(continuousInfo[i].sourceSubIdx);
-		 if (createGroupIfDoesNotExist(basePath)) return false;
-		 basePath = basePath + "/recording" + String(recordingNumber);
-		 if (createGroup(basePath)) return false;
-		 dSet = createRecordingStructures(basePath, continuousInfo[i], "Stores acquired voltage data from extracellular recordings", CHUNK_XSIZE, "ElectricalSeries");
-		 continuousDataSetsTS.add(dSet);
-		 basePath += "/data";
-		 continuousBasePaths.add(basePath);
-		 dSet = createDataSet(I16, 0, continuousInfo[i].nChannels, CHUNK_XSIZE, basePath);
-		 continuousDataSets.add(dSet); //even if it's null, to not break ordering.
-		 if (!dSet)
-			 std::cerr << "Error creating data dataset for " << continuousInfo[i].processorId << std::endl;
+		 //All channels in a group will share the same source information (any caller to this method MUST assure this happen
+		 //so we just pick the first channel.
+		 const DataChannel* info = continuousArray.getReference(i)[0];
+		 basePath = rootPath + "/continuous/processor" + String(info->getCurrentNodeID()) + "_" + String(info->getSourceNodeID());
+		 if (info->getSourceSubprocessorCount() > 1) basePath += "." + String(info->getSubProcessorIdx());
+		 String name = info->getCurrentNodeName() + " (" + String(info->getCurrentNodeID()) + ") From " + info->getSourceName() + " (" + String(info->getSourceNodeID());
+		 if (info->getSourceSubprocessorCount() > 1) name += "." + String(info->getSubProcessorIdx());
+		 name += ")";
+		 ancestry.clearQuick();
+		 ancestry.add("Timeseries");
+		 ancestry.add("ElectricalSeries");
+		 if (!createTimeSeriesBase(basePath, name, "Stores acquired voltage data from extracellular recordings", "", ancestry)) return false;
+		 tsStruct = new TimeSeries();
+		 tsStruct->basePath = basePath;
+		 dSet = createDataSet(BaseDataType::I16, 0, continuousArray.getReference(i).size(), CHUNK_XSIZE, basePath + "/data");
+		 if (dSet == nullptr)
+		 {
+			 std::cerr << "Error creating dataset for " << name << std::endl;
+			 return false;
+		 }
 		 else
 		 {
-			 float bV = continuousInfo[i].bitVolts;
-			 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-			 bV = bV / float(65536);
-			 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-			 CHECK_ERROR(setAttributeStr("volt", basePath, "unit"));
+			 createDataAttributes(basePath, info->getBitVolts(), info->getBitVolts() / 65536, info->getDataUnits());
 		 }
-		 continuousInfoStructs.add(continuousInfo[i]);
-	 }
+		 tsStruct->baseDataSet = dSet;
+
+		 dSet = createTimestampDataSet(basePath, CHUNK_XSIZE);
+		 if (dSet == nullptr) return false;
+		 tsStruct->timestampDataSet = dSet;
 
-	 nCont = spikeInfo.size();
+		 basePath = basePath + "/oe_extra_info";
+		 if (createGroup(basePath)) return false;
+		 int nChans = continuousArray.getReference(i).size();
+		 for (int j = 0; j < nChans; j++)
+		 {
+			 String channelPath = basePath + "/channel" + String(j + 1);
+			 const DataChannel* chan = continuousArray.getReference(i)[j];
+			 createExtraInfo(channelPath, chan->getName(), chan->getDescription(), chan->getIdentifier(), chan->getSourceIndex(), chan->getSourceTypeIndex());
+			 createChannelMetaDataSets(channelPath + "/channel_metadata", chan);
+		 }
+		 continuousDataSets.add(tsStruct.release());
+	 }		 
+
+	 nCont = electrodeArray.size();
 	 for (int i = 0; i < nCont; i++)
 	 {
-		 basePath = "/acquisition/timeseries/spikes";
-		 basePath = basePath + "/electrode" + String(i);
-		 if (createGroupIfDoesNotExist(basePath)) return false;
-		 basePath = basePath + "/recording" + String(recordingNumber);
-		 if (createGroup(basePath)) return false;
-		 dSet = createRecordingStructures(basePath, spikeInfo[i], "Snapshorts of spike events from data", SPIKE_CHUNK_XSIZE, "SpikeEventSeries");
-		 spikeDataSetsTS.add(dSet);
-		 basePath += "/data";
-		 spikeBasePaths.add(basePath);
-		 dSet = createDataSet(I16, 0, spikeInfo[i].nChannels, spikeInfo[i].nSamplesPerSpike, SPIKE_CHUNK_XSIZE, basePath);
-		 spikeDataSets.add(dSet); //even if it's null, to not break ordering.
-		 if (!dSet)
-			 std::cerr << "Error creating spike dataset for " << spikeInfo[i].processorId << std::endl;
+		 basePath = rootPath + "/spikes/electrode" + String(i + 1);
+		 const SpikeChannel* info = electrodeArray[i];
+		 String sourceName = info->getSourceName() + "_" + String(info->getSourceNodeID());
+		 if (info->getSourceSubprocessorCount() > 1) sourceName = sourceName + "." + String(info->getSubProcessorIdx());
+		 ancestry.clearQuick();
+		 ancestry.add("Timeseries");
+		 ancestry.add("SpikeEventSeries");
+		 if (!createTimeSeriesBase(basePath, sourceName, "Snapshorts of spike events from data", info->getName(), ancestry)) return false;
+
+		 tsStruct = new TimeSeries();
+		 tsStruct->basePath = basePath;
+
+		 dSet = createDataSet(BaseDataType::I16, 0, info->getNumChannels(), info->getTotalSamples(), SPIKE_CHUNK_XSIZE, basePath + "/data");
+		 if (dSet == nullptr)
+		 {
+			 std::cerr << "Error creating dataset for electrode " << i << std::endl;
+			 return false;
+		 }
 		 else
 		 {
-			 float bV = spikeInfo[i].bitVolts;
-			 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-			 bV = bV / float(65536);
-			 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-			 CHECK_ERROR(setAttributeStr("volt", basePath, "unit"));
+			 createDataAttributes(basePath, info->getChannelBitVolts(0), info->getChannelBitVolts(0) / 65536, "volt");
 		 }
-		 spikeInfoStructs.add(spikeInfo[i]);
-		 numSpikes.add(0);
+		 tsStruct->baseDataSet = dSet;
+		 dSet = createTimestampDataSet(basePath, SPIKE_CHUNK_XSIZE);
+		 if (dSet == nullptr) return false;
+		 tsStruct->timestampDataSet = dSet;
+
+		 basePath = basePath + "/oe_extra_info";
+		 createExtraInfo(basePath, info->getName(), info->getDescription(), info->getIdentifier(), info->getSourceIndex(), info->getSourceTypeIndex());
+		 createChannelMetaDataSets(basePath + "/channel_metadata", info);
+		 createEventMetaDataSets(basePath + "/spike_metadata", tsStruct, info);
+
+		 spikeDataSets.add(tsStruct.release());
+
 
 	 }
+	
+	 nCont = eventArray.size();
+	 int nTTL = 0;
+	 int nTXT = 0;
+	 int nBIN = 0;
+	 for (int i = 0; i < nCont; i++)
+	 {
+		 basePath = rootPath + "/events";
+		 const EventChannel* info = eventArray[i];
+		 String sourceName = info->getSourceName() + "_" + String(info->getSourceNodeID());
+		 if (info->getSourceSubprocessorCount() > 1) sourceName = sourceName + "." + String(info->getSubProcessorIdx());
+		 ancestry.clearQuick();
+		 ancestry.add("Timeseries");
 
-	 NWBRecordingInfo singleInfo;
-	 singleInfo.bitVolts = NAN;
-	 singleInfo.nChannels = 0;
-	 singleInfo.nSamplesPerSpike = 0;
-	 singleInfo.processorId = 0;
-	 singleInfo.sampleRate = 0;
-	 singleInfo.sourceId = 0;
-	 singleInfo.spikeElectrodeName = " ";
-	 singleInfo.sourceName = "All processors";
-
-	 basePath = "/acquisition/timeseries/events";
-	 basePath = basePath + "/recording" + String(recordingNumber);
-	 if (createGroup(basePath)) return false;
-	 dSet = createRecordingStructures(basePath, singleInfo, "Stores the start and stop times for events",EVENT_CHUNK_SIZE, "IntervalSeries");
-	 eventsDataSetTS = dSet;
-	 eventsControlDataSet = createDataSet(U8, 0, EVENT_CHUNK_SIZE, basePath + "/control");
-	 if (!eventsControlDataSet)
-		 std::cerr << "Error creating events control dataset" << std::endl;
-
-	 basePath += "/data";
-	 eventsBasePath = basePath;
-	 dSet = createDataSet(I8, 0, EVENT_CHUNK_SIZE, basePath);
-	 eventsDataSet = dSet; //even if it's null, to not break ordering.
-	 if (!dSet)
-		 std::cerr << "Error creating events dataset " << std::endl;
-	 else
+		 String helpText;
+
+		 switch (info->getChannelType())
+		 {
+		 case EventChannel::TTL:
+			 nTTL += 1;
+			 basePath = basePath + "/ttl" + String(nTTL);
+			 ancestry.add("IntervalSeries");
+			 ancestry.add("TTLSeries");
+			 helpText = "Stores the start and stop times for TTL events";
+			 break;
+		 case EventChannel::TEXT:
+			 nTXT += 1;
+			 basePath = basePath + "/text" + String(nTXT);
+			 ancestry.add("AnnotationSeries");
+			 helpText = "Time-stamped annotations about an experiment";
+			 break;
+		 default:
+			 nBIN += 1;
+			 basePath = basePath + "/binary" + String(nBIN);
+			 ancestry.add("BinarySeries");
+			 helpText = "Stores arbitrary binary data";
+			 break;
+		 }
+
+		 if (!createTimeSeriesBase(basePath, sourceName, helpText, info->getDescription(), ancestry)) return false;
+
+		 tsStruct = new TimeSeries();
+		 tsStruct->basePath = basePath;
+
+		 if (info->getChannelType() >= EventChannel::BINARY_BASE_VALUE) //only binary events have length greater than 1
+		 {
+			 dSet = createDataSet(getEventH5Type(info->getChannelType(), info->getLength()), 0, info->getLength(), EVENT_CHUNK_SIZE, basePath + "/data");;
+		 }
+		 else
+		 {
+			 dSet = createDataSet(getEventH5Type(info->getChannelType(), info->getLength()), 0, EVENT_CHUNK_SIZE, basePath + "/data");
+		 }
+
+		 if (dSet == nullptr)
+		 {
+			 std::cerr << "Error creating dataset for event " << info->getName() << std::endl;
+			 return false;
+		 }
+		 else
+		 {
+			 createDataAttributes(basePath, NAN, NAN, "n/a");
+		 }
+
+
+		 tsStruct->baseDataSet = dSet;
+		 dSet = createTimestampDataSet(basePath, EVENT_CHUNK_SIZE);
+		 if (dSet == nullptr) return false;
+		 tsStruct->timestampDataSet = dSet;
+
+		 dSet = createDataSet(BaseDataType::U8, 0, EVENT_CHUNK_SIZE, basePath + "/control");
+		 if (dSet == nullptr) return false;
+		 tsStruct->controlDataSet = dSet;
+
+		 if (info->getChannelType() == EventChannel::TTL)
+		 {
+			 dSet = createDataSet(BaseDataType::U8, 0, info->getDataSize(), EVENT_CHUNK_SIZE, basePath + "/full_word");
+			 if (dSet == nullptr) return false;
+			 tsStruct->ttlWordDataSet = dSet;
+		 }
+
+		 basePath = basePath + "/oe_extra_info";
+		 createExtraInfo(basePath, info->getName(), info->getDescription(), info->getIdentifier(), info->getSourceIndex(), info->getSourceTypeIndex());
+		 createChannelMetaDataSets(basePath + "/channel_metadata", info);
+		 createEventMetaDataSets(basePath + "/event_metadata", tsStruct, info);
+		 eventDataSets.add(tsStruct.release());
+
+	 }
+	 basePath = rootPath + "/events/sync_messages";
+	 ancestry.clearQuick();
+	 ancestry.add("Timeseries");
+	 ancestry.add("AnnotationSeries");
+	 String desc = "Stores recording start timestamps for each processor in text format";
+	 if (!createTimeSeriesBase(basePath, "Autogenerated messages", desc, desc, ancestry)) return false;
+	 tsStruct = new TimeSeries();
+	 tsStruct->basePath = basePath;
+	 dSet = createDataSet(BaseDataType::STR(100), 0, 1, basePath + "/data");
+	 if (dSet == nullptr)
 	 {
-		 float bV = NAN;
-		 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-		 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-		 CHECK_ERROR(setAttributeStr("n/a", basePath, "unit"));
+		 std::cerr << "Error creating dataset for sync messages" << std::endl;
+		 return false;
 	 }
-	 numEvents = 0;
-
-	 basePath = "/acquisition/timeseries/messages";
-	 basePath = basePath + "/recording" + String(recordingNumber);
-	 if (createGroup(basePath)) return false;
-	 dSet = createRecordingStructures(basePath, singleInfo, "Time-stamped annotations about an experiment", EVENT_CHUNK_SIZE, "AnnotationSeries");
-	 messagesDataSetTS = dSet;
-	 basePath += "/data";
-	 messagesBasePath = basePath;
-	 dSet = createDataSet(STR, 0, EVENT_CHUNK_SIZE, basePath);
-	 messagesDataSet = dSet; //even if it's null, to not break ordering.
-	 if (!dSet)
-		 std::cerr << "Error creating messages dataset " << std::endl;
 	 else
 	 {
-		 float bV = NAN;
-		 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-		 CHECK_ERROR(setAttribute(F32, &bV, basePath, "resolution"));
-		 CHECK_ERROR(setAttributeStr("n/a", basePath, "unit"));
+		 createDataAttributes(basePath, NAN, NAN, "n/a");
 	 }
-	 numMessages = 0;
+	 tsStruct->baseDataSet = dSet;
+	 dSet = createTimestampDataSet(basePath, 1);
+	 if (dSet == nullptr) return false;
+	 tsStruct->timestampDataSet = dSet;
+
+	 dSet = createDataSet(BaseDataType::U8, 0, 1, basePath + "/control");
+	 if (dSet == nullptr) return false;
+	 tsStruct->controlDataSet = dSet;
+	 syncMsgDataSet = tsStruct;
+
 	 return true;
  }
  
  void NWBFile::stopRecording()
  {
-	 uint64 n;
 	 int nObjs = continuousDataSets.size();
+	 const TimeSeries* tsStruct;
 	 for (int i = 0; i < nObjs; i++)
 	 {
-		 n = numContinuousSamples[i];
-		 CHECK_ERROR(setAttribute(U64, &n, continuousBasePaths[i], "num_samples"));
+		 tsStruct = continuousDataSets[i];
+		 CHECK_ERROR(setAttribute(BaseDataType::U64, &(tsStruct->numSamples), tsStruct->basePath, "num_samples"));
 	 }
 	 nObjs = spikeDataSets.size();
 	 for (int i = 0; i < nObjs; i++)
 	 {
-		 n = numSpikes[i];
-		 CHECK_ERROR(setAttribute(I32, &n, spikeBasePaths[i], "num_samples"));
+		 tsStruct = spikeDataSets[i];
+		 CHECK_ERROR(setAttribute(BaseDataType::U64, &(tsStruct->numSamples), tsStruct->basePath, "num_samples"));
 	 }
-	 CHECK_ERROR(setAttribute(I32, &numEvents, eventsBasePath, "num_samples"));
-	 CHECK_ERROR(setAttribute(I32, &numMessages, messagesBasePath, "num_samples"));
+	 nObjs = eventDataSets.size();
+	 for (int i = 0; i < nObjs; i++)
+	 {
+		 tsStruct = eventDataSets[i];
+		 CHECK_ERROR(setAttribute(BaseDataType::U64, &(tsStruct->numSamples), tsStruct->basePath, "num_samples"));
+	 }
+	 
+	 CHECK_ERROR(setAttribute(BaseDataType::U64, &(syncMsgDataSet->numSamples), syncMsgDataSet->basePath, "num_samples"));
 
 	 continuousDataSets.clear();
-	 continuousDataSetsTS.clear();
-	 continuousBasePaths.clear();
-	 numContinuousSamples.clear();
-
 	 spikeDataSets.clear();
-	 spikeDataSetsTS.clear();
-	 spikeBasePaths.clear();
-	 numSpikes.clear();
-
-	 eventsDataSet = nullptr;
-	 eventsDataSetTS = nullptr;
-	 eventsControlDataSet = nullptr;
-
-	 messagesDataSet = nullptr;
-	 messagesDataSetTS = nullptr;
-
+	 eventDataSets.clear();
+	 syncMsgDataSet = nullptr;
  }
  
- void NWBFile::writeData(int datasetID, int channel, int nSamples, const int16* data)
+ void NWBFile::writeData(int datasetID, int channel, int nSamples, const float* data, float bitVolts)
  {
 	 if (!continuousDataSets[datasetID])
 		 return;
 
-	 CHECK_ERROR(continuousDataSets[datasetID]->writeDataRow(channel, nSamples, I16, data));
+	 if (nSamples > bufferSize) //Shouldn't happen, and if it happens it'll be slow, but better this than crashing. Will be reset on file close and reset.
+	 {
+		 std::cerr << "Write buffer overrun, resizing to" << nSamples << std::endl;
+		 bufferSize = nSamples;
+		 scaledBuffer.malloc(nSamples);
+		 intBuffer.malloc(nSamples);
+	 }
+
+	 double multFactor = 1 / (float(0x7fff) * bitVolts);
+	 FloatVectorOperations::copyWithMultiply(scaledBuffer.getData(), data, multFactor, nSamples);
+	 AudioDataConverters::convertFloatToInt16LE(scaledBuffer.getData(), intBuffer.getData(), nSamples);
+
+	 CHECK_ERROR(continuousDataSets[datasetID]->baseDataSet->writeDataRow(channel, nSamples, BaseDataType::I16, intBuffer));
 	 
 	 /* Since channels are filled asynchronouysly by the Record Thread, there is no guarantee
 		that at a any point in time all channels in a dataset have the same number of filled samples.
@@ -256,80 +371,304 @@ int NWBFile::createFileStructure()
 		an arbitrary channel, and at the end all channels will be the same. */
 
 	 if (channel == 0) //there will always be a first channel or there wouldn't be dataset
-		 numContinuousSamples.set(datasetID, numContinuousSamples[datasetID] + nSamples);
+		 continuousDataSets[datasetID]->numSamples += nSamples;
  }
 
  void NWBFile::writeTimestamps(int datasetID, int nSamples, const double* data)
  {
-	 if (!continuousDataSetsTS[datasetID])
+	 if (!continuousDataSets[datasetID])
 		 return;
 
-	 CHECK_ERROR(continuousDataSetsTS[datasetID]->writeDataBlock(nSamples, F64, data));
+	 CHECK_ERROR(continuousDataSets[datasetID]->timestampDataSet->writeDataBlock(nSamples, BaseDataType::F64, data));
  }
 
- void NWBFile::writeSpike(int electrodeId, const int16* data, double timestampSec)
+ void NWBFile::writeSpike(int electrodeId, const SpikeChannel* channel, const SpikeEvent* event)
  {
 	 if (!spikeDataSets[electrodeId])
 		 return;
-	 int totValues = spikeInfoStructs[electrodeId].nChannels * spikeInfoStructs[electrodeId].nSamplesPerSpike;
-	 CHECK_ERROR(spikeDataSets[electrodeId]->writeDataBlock(1, I16, data));
-	 CHECK_ERROR(spikeDataSetsTS[electrodeId]->writeDataBlock(1, F64, &timestampSec));
-	 numSpikes.set(electrodeId, numSpikes[electrodeId] + 1);
+	 int nSamples = channel->getTotalSamples() * channel->getNumChannels();
+
+	 if (nSamples > bufferSize) //Shouldn't happen, and if it happens it'll be slow, but better this than crashing. Will be reset on file close and reset.
+	 {
+		 std::cerr << "Write buffer overrun, resizing to" << nSamples << std::endl;
+		 bufferSize = nSamples;
+		 scaledBuffer.malloc(nSamples);
+		 intBuffer.malloc(nSamples);
+	 }
+
+	 double multFactor = 1 / (float(0x7fff) * channel->getChannelBitVolts(0));
+	 FloatVectorOperations::copyWithMultiply(scaledBuffer.getData(), event->getDataPointer(), multFactor, nSamples);
+	 AudioDataConverters::convertFloatToInt16LE(scaledBuffer.getData(), intBuffer.getData(), nSamples);
+
+	 double timestampSec = event->getTimestamp() / channel->getSampleRate();
+
+	 CHECK_ERROR(spikeDataSets[electrodeId]->baseDataSet->writeDataBlock(1, BaseDataType::I16, intBuffer));
+	 CHECK_ERROR(spikeDataSets[electrodeId]->timestampDataSet->writeDataBlock(1, BaseDataType::F64, &timestampSec));
+	 writeEventMetaData(spikeDataSets[electrodeId], channel, event);
+
+	 spikeDataSets[electrodeId]->numSamples += 1;
 
  }
 
- void NWBFile::writeTTLEvent(int channel, int id, uint8 source, double timestampSec)
+ void NWBFile::writeEvent(int eventID, const EventChannel* channel, const Event* event)
  {
-	 int8 data = id != 0 ? channel : -channel;
-	 CHECK_ERROR(eventsDataSet->writeDataBlock(1, I8, &data));
-	 CHECK_ERROR(eventsDataSetTS->writeDataBlock(1, F64, &timestampSec));
-	 CHECK_ERROR(eventsControlDataSet->writeDataBlock(1, U8, &source));
-	 numEvents += 1;
+	 if (!eventDataSets[eventID])
+		 return;
+	 
+	 const void* dataSrc;
+	 BaseDataType type;
+	 int8 ttlVal;
+	 String text;
+
+	 switch (event->getEventType())
+	 {
+	 case EventChannel::TTL:
+		 ttlVal = (static_cast<const TTLEvent*>(event)->getState() ? 1 : -1) * (event->getChannel() + 1);
+		 dataSrc = &ttlVal;
+		 type = BaseDataType::I8;
+		 break;
+	 case EventChannel::TEXT:
+		 text = static_cast<const TextEvent*>(event)->getText();
+		 dataSrc = text.toUTF8().getAddress();
+		 type = BaseDataType::STR(text.length());
+		 break;
+	 default:
+		 dataSrc = static_cast<const BinaryEvent*>(event)->getBinaryDataPointer();
+		 type = getEventH5Type(event->getEventType());
+		 break;
+	 }
+	 CHECK_ERROR(eventDataSets[eventID]->baseDataSet->writeDataBlock(1, type, dataSrc));
+
+	 double timeSec = event->getTimestamp() / channel->getSampleRate();
+
+	 CHECK_ERROR(eventDataSets[eventID]->timestampDataSet->writeDataBlock(1, BaseDataType::F64, &timeSec));
+
+	 uint8 controlValue = event->getChannel() + 1;
+
+	 CHECK_ERROR(eventDataSets[eventID]->controlDataSet->writeDataBlock(1, BaseDataType::U8, &controlValue));
+
+	 if (event->getEventType() == EventChannel::TTL)
+	 {
+		 CHECK_ERROR(eventDataSets[eventID]->ttlWordDataSet->writeDataBlock(1, BaseDataType::U8, static_cast<const TTLEvent*>(event)->getTTLWordPointer()));
+	 }
+	 
+	 eventDataSets[eventID]->numSamples += 1;
  }
 
- void NWBFile::writeMessage(const char* msg, double timestampSec)
+ void NWBFile::writeTimestampSyncText(uint16 sourceID, int64 timestamp, float sourceSampleRate, String text)
  {
-	 CHECK_ERROR(messagesDataSet->writeDataBlock(1, STR, msg));
-	 CHECK_ERROR(messagesDataSetTS->writeDataBlock(1, F64, &timestampSec));
-	 numMessages += 1;
+	 CHECK_ERROR(syncMsgDataSet->baseDataSet->writeDataBlock(1, BaseDataType::STR(text.length()), text.toUTF8()));
+	 double timeSec = timestamp / sourceSampleRate;
+	 CHECK_ERROR(syncMsgDataSet->timestampDataSet->writeDataBlock(1, BaseDataType::F64, &timeSec));
+	 CHECK_ERROR(syncMsgDataSet->controlDataSet->writeDataBlock(1, BaseDataType::U8, &sourceID));
+	 syncMsgDataSet->numSamples += 1;
  }
+
  
  String NWBFile::getFileName()
  {
 	 return filename;
  }
 
-  HDF5RecordingData* NWBFile::createRecordingStructures(String basePath, const NWBRecordingInfo& info, String helpText, int chunk_size, String ancestry)
+  bool NWBFile::createTimeSeriesBase(String basePath, String source, String helpText, String description, StringArray ancestry)
  {
-	 StringArray ancestryStrings;
-	 ancestryStrings.add("TimeSeries");
-	 ancestryStrings.add(ancestry);
-	 CHECK_ERROR(setAttributeStrArray(ancestryStrings, basePath, "ancestry"));
+	 if (createGroup(basePath)) return false;
+	 CHECK_ERROR(setAttributeStrArray(ancestry, basePath, "ancestry"));
 	 CHECK_ERROR(setAttributeStr(" ", basePath, "comments"));
-	 CHECK_ERROR(setAttributeStr(info.spikeElectrodeName, basePath, "description"));
+	 CHECK_ERROR(setAttributeStr(description, basePath, "description"));
 	 CHECK_ERROR(setAttributeStr("TimeSeries", basePath, "neurodata_type"));
-	 CHECK_ERROR(setAttributeStr(info.sourceName, basePath, "source"));
+	 CHECK_ERROR(setAttributeStr(source, basePath, "source"));
 	 CHECK_ERROR(setAttributeStr(helpText, basePath, "help"));
-	 HDF5RecordingData* tsSet = createDataSet(HDF5FileBase::F64, 0, chunk_size, basePath + "/timestamps");
-	 if (!tsSet)
-		 std::cerr << "Error creating timestamp dataset for " << info.processorId << std::endl;
-	 else
-	 {
-		 const int32 one = 1;
-		 CHECK_ERROR(setAttribute(HDF5FileBase::I32, &one, basePath + "/timestamps", "interval"));
-		 CHECK_ERROR(setAttributeStr("seconds", basePath + "/timestamps", "unit"));
-	 }
-	 return tsSet;
-
+	 return true;
  }
+
+  void NWBFile::createDataAttributes(String basePath, float conversion, float resolution, String unit)
+  {
+		  CHECK_ERROR(setAttribute(BaseDataType::F32, &conversion, basePath + "/data", "conversion"));
+		  CHECK_ERROR(setAttribute(BaseDataType::F32, &resolution, basePath + "/data", "resolution"));
+		  CHECK_ERROR(setAttributeStr(unit, basePath + "/data", "unit"));
+  }
+
+  HDF5RecordingData* NWBFile::createTimestampDataSet(String basePath, int chunk_size)
+  {
+	  HDF5RecordingData* tsSet = createDataSet(BaseDataType::F64, 0, chunk_size, basePath + "/timestamps");
+	  if (!tsSet)
+		  std::cerr << "Error creating timestamp dataset in " << basePath << std::endl;
+	  else
+	  {
+		  const int32 one = 1;
+		  CHECK_ERROR(setAttribute(BaseDataType::I32, &one, basePath + "/timestamps", "interval"));
+		  CHECK_ERROR(setAttributeStr("seconds", basePath + "/timestamps", "unit"));
+	  }
+	  return tsSet;
+  }
+
+  bool NWBFile::createExtraInfo(String basePath, String name, String desc, String id, uint16 index, uint16 typeIndex)
+  {
+	  if (createGroup(basePath)) return false;
+	  CHECK_ERROR(setAttributeStr("openephys:<channel_info>/", basePath, "schema_id"));
+	  CHECK_ERROR(setAttributeStr(name, basePath, "name"));
+	  CHECK_ERROR(setAttributeStr(desc, basePath, "description"));
+	  CHECK_ERROR(setAttributeStr(id, basePath, "identifier"));
+	  CHECK_ERROR(setAttribute(BaseDataType::U16, &index, basePath, "source_index"));
+	  CHECK_ERROR(setAttribute(BaseDataType::U16, &typeIndex, basePath, "source_type_index"));
+	  return true;
+  }
+
+  bool NWBFile::createChannelMetaDataSets(String basePath, const MetaDataInfoObject* info)
+  {
+	  if (!info) return false;
+	  if (createGroup(basePath)) return false;
+	  CHECK_ERROR(setAttributeStr("openephys:<metadata>/", basePath, "schema_id"));
+	  int nMetaData = info->getMetaDataCount();
+	  
+	  for (int i = 0; i < nMetaData; i++)
+	  {
+		  const MetaDataDescriptor* desc = info->getMetaDataDescriptor(i);
+		  String fieldName = "Field_" + String(i+1);
+		  String name = desc->getName();
+		  String description = desc->getDescription();
+		  String identifier = desc->getIdentifier();
+		  BaseDataType type = getMetaDataH5Type(desc->getType(), desc->getLength()); //only string types use length, for others is always set to 1. If array types are implemented, change this
+		  int length = desc->getType() == MetaDataDescriptor::CHAR ? 1 : desc->getLength(); //strings are a single element of length set in the type (see above) while other elements are saved a
+		  HeapBlock<char> data(desc->getDataSize());
+		  info->getMetaDataValue(i)->getValue(static_cast<void*>(data.getData()));
+		  createBinaryDataSet(basePath, fieldName, type, length, data.getData());
+		  String fullPath = basePath + "/" + fieldName;
+		  CHECK_ERROR(setAttributeStr("openephys:<metadata>/", fullPath, "schema_id"));
+		  CHECK_ERROR(setAttributeStr(name, fullPath, "name"));
+		  CHECK_ERROR(setAttributeStr(description, fullPath, "description"));
+		  CHECK_ERROR(setAttributeStr(identifier, fullPath, "identifier"));
+	  }
+	  return true;
+  }
+
+ 
+  bool NWBFile::createEventMetaDataSets(String basePath, TimeSeries* timeSeries, const MetaDataEventObject* info)
+  {
+	  if (!info) return false;
+	  if (createGroup(basePath)) return false;
+	  CHECK_ERROR(setAttributeStr("openephys:<metadata>/", basePath, "schema_id"));
+	  int nMetaData = info->getEventMetaDataCount();
+
+	  timeSeries->metaDataSet.clear(); //just in case
+	  for (int i = 0; i < nMetaData; i++)
+	  {
+		  const MetaDataDescriptor* desc = info->getEventMetaDataDescriptor(i);
+		  String fieldName = "Field_" + String(i+1);
+		  String name = desc->getName();
+		  String description = desc->getDescription();
+		  String identifier = desc->getIdentifier();
+		  BaseDataType type = getMetaDataH5Type(desc->getType(), desc->getLength()); //only string types use length, for others is always set to 1. If array types are implemented, change this
+		  int length = desc->getType() == MetaDataDescriptor::CHAR ? 1 : desc->getLength(); //strings are a single element of length set in the type (see above) while other elements are saved as arrays
+		  String fullPath = basePath + "/" + fieldName;
+		  HDF5RecordingData* dSet = createDataSet(type, 0, length, EVENT_CHUNK_SIZE, fullPath);
+		  if (!dSet) return false;
+		  timeSeries->metaDataSet.add(dSet);
+
+		  CHECK_ERROR(setAttributeStr("openephys:<metadata>/", fullPath, "schema_id"));
+		  CHECK_ERROR(setAttributeStr(name, fullPath, "name"));
+		  CHECK_ERROR(setAttributeStr(description, fullPath, "description"));
+		  CHECK_ERROR(setAttributeStr(identifier, fullPath, "identifier"));
+	  }
+      return true;
+  }
+
+  void NWBFile::writeEventMetaData(TimeSeries* timeSeries, const MetaDataEventObject* info, const MetaDataEvent* event)
+  {
+	  jassert(timeSeries->metaDataSet.size() == event->getMetadataValueCount());
+	  jassert(info->getEventMetaDataCount() == event->getMetadataValueCount());
+	  int nMetaData = event->getMetadataValueCount();
+	  for (int i = 0; i < nMetaData; i++)
+	  {
+		  BaseDataType type = getMetaDataH5Type(info->getEventMetaDataDescriptor(i)->getType(), info->getEventMetaDataDescriptor(i)->getLength());
+		  timeSeries->metaDataSet[i]->writeDataBlock(1, type, event->getMetaDataValue(i)->getRawValuePointer());
+	  }
+
+  }
  
   void NWBFile::createTextDataSet(String path, String name, String text)
   {
 	  ScopedPointer<HDF5RecordingData> dSet;
 
 	  if (text.isEmpty()) text = " "; //to avoid 0-length strings, which cause errors
+	  BaseDataType type = BaseDataType::STR(text.length());
 
-	  dSet = createDataSet(STR, 1, 0, path + "/" + name);
+	  dSet = createDataSet(type, 1, 0, path + "/" + name);
 	  if (!dSet) return;
-	  dSet->writeDataBlock(1, STR, text.toUTF8());
+	  dSet->writeDataBlock(1, type, text.toUTF8());
   }
+
+  void NWBFile::createBinaryDataSet(String path, String name, BaseDataType type, int length, void* data)
+  {
+	  ScopedPointer<HDF5RecordingData> dSet;
+	  if ((length < 1) || !data) return;
+
+	  dSet = createDataSet(type, 1, length, 1, path + "/" + name);
+	  if (!dSet) return;
+	  dSet->writeDataBlock(1, type, data);
+  }
+
+
+  //These two methods whould be easy to adapt to support array types for all base types, for now
+  //length is only used for string types.
+  NWBFile::BaseDataType NWBFile::getEventH5Type(EventChannel::EventChannelTypes type, int length)
+  {
+	  switch (type)
+	  {
+	  case EventChannel::INT8_ARRAY:
+		  return BaseDataType::I8;
+	  case EventChannel::UINT8_ARRAY:
+		  return BaseDataType::U8;
+	  case EventChannel::INT16_ARRAY:
+		  return BaseDataType::I16;
+	  case EventChannel::UINT16_ARRAY:
+		  return BaseDataType::U16;
+	  case EventChannel::INT32_ARRAY:
+		  return BaseDataType::I32;
+	  case EventChannel::UINT32_ARRAY:
+		  return BaseDataType::U32;
+	  case EventChannel::INT64_ARRAY:
+		  return BaseDataType::I64;
+	  case EventChannel::UINT64_ARRAY:
+		  return BaseDataType::U64;
+	  case EventChannel::FLOAT_ARRAY:
+		  return BaseDataType::F32;
+	  case EventChannel::DOUBLE_ARRAY:
+		  return BaseDataType::F64;
+	  case EventChannel::TEXT:
+		  return BaseDataType::STR(length);
+	  default:
+		  return BaseDataType::I8;
+	  }
+  }
+  NWBFile::BaseDataType NWBFile::getMetaDataH5Type(MetaDataDescriptor::MetaDataTypes type, int length)
+  {
+	  switch (type)
+	  {
+	  case MetaDataDescriptor::INT8:
+		  return BaseDataType::I8;
+	  case MetaDataDescriptor::UINT8:
+		  return BaseDataType::U8;
+	  case MetaDataDescriptor::INT16:
+		  return BaseDataType::I16;
+	  case MetaDataDescriptor::UINT16:
+		  return BaseDataType::U16;
+	  case MetaDataDescriptor::INT32:
+		  return BaseDataType::I32;
+	  case MetaDataDescriptor::UINT32:
+		  return BaseDataType::U32;
+	  case MetaDataDescriptor::INT64:
+		  return BaseDataType::I64;
+	  case MetaDataDescriptor::UINT64:
+		  return BaseDataType::U64;
+	  case MetaDataDescriptor::FLOAT:
+		  return BaseDataType::F32;
+	  case MetaDataDescriptor::DOUBLE:
+		  return BaseDataType::F64;
+	  case MetaDataDescriptor::CHAR:
+		  return BaseDataType::STR(length);
+	  default:
+		  return BaseDataType::I8;
+	  }
+  }
\ No newline at end of file
diff --git a/Source/Plugins/NWBFormat/NWBFormat.h b/Source/Plugins/NWBFormat/NWBFormat.h
index b64491c38164d86793950c4763a56389521be413..bf5fb79b26a3caeeeb8741146e2c20b09d8e3627 100644
--- a/Source/Plugins/NWBFormat/NWBFormat.h
+++ b/Source/Plugins/NWBFormat/NWBFormat.h
@@ -25,22 +25,22 @@
 #define NWBFORMAT_H
 
 #include <OpenEphysHDF5Lib/HDF5FileFormat.h>
+#include <RecordingLib.h>
 using namespace OpenEphysHDF5;
 
 namespace NWBRecording
 {
-
-	struct NWBRecordingInfo
+	typedef Array<const DataChannel*> ContinuousGroup;
+	class TimeSeries
 	{
-		String sourceName;
-		float bitVolts;
-		int processorId;
-		int sourceId;
-		int sourceSubIdx;
-		int nChannels;
-		int nSamplesPerSpike;
-		float sampleRate;
-		String spikeElectrodeName;
+	public:
+		ScopedPointer<HDF5RecordingData> baseDataSet;
+		ScopedPointer<HDF5RecordingData> timestampDataSet;
+		ScopedPointer<HDF5RecordingData> controlDataSet; //for all but spikes
+		ScopedPointer<HDF5RecordingData> ttlWordDataSet; //just for ttl events
+		OwnedArray<HDF5RecordingData> metaDataSet;
+		String basePath;
+		uint64 numSamples{ 0 };
 	};
 
 	class NWBFile : public HDF5FileBase
@@ -48,13 +48,14 @@ namespace NWBRecording
 	public:
 		NWBFile(String fName, String ver, String idText); //with whatever arguments it's necessary
 		~NWBFile();
-		bool startNewRecording(int recordingNumber, const Array<NWBRecordingInfo>& continuousArray, const Array<NWBRecordingInfo>& electrodeArray);
+		bool startNewRecording(int recordingNumber, const Array<ContinuousGroup>& continuousArray,
+			const Array<const EventChannel*>& eventArray, const Array<const SpikeChannel*>& electrodeArray);
 		void stopRecording();
-		void writeData(int datasetID, int channel, int nSamples, const int16* data);
+		void writeData(int datasetID, int channel, int nSamples, const float* data, float bitVolts);
 		void writeTimestamps(int datasetID, int nSamples, const double* data);
-		void writeSpike(int electrodeId, const int16* data, double timestampSec);
-		void writeTTLEvent(int channel, int id, uint8 source, double timestampSec);
-		void writeMessage(const char* msg, double timestampSec);
+		void writeSpike(int electrodeId, const SpikeChannel* channel, const SpikeEvent* event);
+		void writeEvent(int eventID, const EventChannel* channel, const Event* event);
+		void writeTimestampSyncText(uint16 sourceID, int64 timestamp, float sourceSampleRate, String text);
 		String getFileName() override;
 		void setXmlText(const String& xmlText);
 
@@ -62,36 +63,37 @@ namespace NWBRecording
 		int createFileStructure() override;
 
 	private:
-		HDF5RecordingData* createRecordingStructures(String basePath, const NWBRecordingInfo& info, String helpText, int chunk_size, String ancestry);
+
 		void createTextDataSet(String path, String name, String text);
+		void createBinaryDataSet(String path, String name, HDF5FileBase::BaseDataType type, int length, void* data);
+		static HDF5FileBase::BaseDataType getEventH5Type(EventChannel::EventChannelTypes type, int length = 1);
+		static HDF5FileBase::BaseDataType getMetaDataH5Type(MetaDataDescriptor::MetaDataTypes type, int length = 1);
+
+		bool createTimeSeriesBase(String basePath, String source, String helpText, String description, StringArray ancestry);
+		bool createExtraInfo(String basePath, String name, String desc, String id, uint16 index, uint16 typeIndex);
+		HDF5RecordingData* createTimestampDataSet(String basePath, int chunk_size);
+		void createDataAttributes(String basePath, float conversion, float resolution, String unit);
+		bool createChannelMetaDataSets(String basePath, const MetaDataInfoObject* info);
+		bool createEventMetaDataSets(String basePath, TimeSeries* timeSeries, const MetaDataEventObject* info);
+
+		void writeEventMetaData(TimeSeries* timeSeries, const MetaDataEventObject* info, const MetaDataEvent* event);
+		
 
 		const String filename;
 		const String GUIVersion;
 
-		OwnedArray<HDF5RecordingData> continuousDataSets;
-		OwnedArray<HDF5RecordingData> continuousDataSetsTS;
-		StringArray continuousBasePaths;
-		Array<uint64> numContinuousSamples;
-		Array<NWBRecordingInfo> continuousInfoStructs;
-		OwnedArray<HDF5RecordingData> spikeDataSets;
-		OwnedArray<HDF5RecordingData> spikeDataSetsTS;
-		StringArray spikeBasePaths;
-		Array<uint64> numSpikes;
-		Array<NWBRecordingInfo> spikeInfoStructs;
-		ScopedPointer<HDF5RecordingData> eventsDataSet;
-		ScopedPointer<HDF5RecordingData> eventsDataSetTS;
-		String eventsBasePath;
-		uint64 numEvents;
-		ScopedPointer<HDF5RecordingData> messagesDataSet;
-		ScopedPointer<HDF5RecordingData> messagesDataSetTS;
-		String messagesBasePath;
-		uint64 numMessages;
-
-		ScopedPointer<HDF5RecordingData> eventsControlDataSet;
+		OwnedArray<TimeSeries>  continuousDataSets;
+		OwnedArray<TimeSeries> spikeDataSets;
+		OwnedArray<TimeSeries> eventDataSets;
+		ScopedPointer<TimeSeries> syncMsgDataSet;
 
 		const String* xmlText;
 		const String identifierText;
 
+		HeapBlock<float> scaledBuffer;
+		HeapBlock<int16> intBuffer;
+		size_t bufferSize;
+
 		JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NWBFile);
 
 	};
diff --git a/Source/Plugins/NWBFormat/NWBRecording.cpp b/Source/Plugins/NWBFormat/NWBRecording.cpp
index 1533888dd74d348040860997304190c7d58729a0..081a4ff9b487fff244ebcaed34403e83a86dfc4d 100644
--- a/Source/Plugins/NWBFormat/NWBRecording.cpp
+++ b/Source/Plugins/NWBFormat/NWBRecording.cpp
@@ -26,10 +26,9 @@
  
  using namespace NWBRecording;
  
- NWBRecordEngine::NWBRecordEngine() : bufferSize(MAX_BUFFER_SIZE)
+ NWBRecordEngine::NWBRecordEngine() 
  {
-	 scaledBuffer.malloc(MAX_BUFFER_SIZE);
-	 intBuffer.malloc(MAX_BUFFER_SIZE);
+	 
 	 tsBuffer.malloc(MAX_BUFFER_SIZE);
  }
  
@@ -55,12 +54,12 @@
 
 	 datasetIndexes.insertMultiple(0, 0, getNumRecordedChannels());
 	 writeChannelIndexes.insertMultiple(0, 0, getNumRecordedChannels());
-	 
+
 	 //Generate the continuous datasets info array, seeking for different combinations of recorded processor and source processor
 	 int lastId = 0;
 	 for (int proc = 0; proc < recProcs; proc++)
 	 {
-		 const RecordProcessorInfo procInfo = getProcessorInfo(proc);
+		 const RecordProcessorInfo& procInfo = getProcessorInfo(proc);
 		 int recChans = procInfo.recordedChannels.size();
 		 for (int chan = 0; chan < recChans; chan++)
 		 {
@@ -69,15 +68,15 @@
 			 const DataChannel* channelInfo = getDataChannel(realChan);
 			 int sourceId = channelInfo->getSourceNodeID();
 			 int sourceSubIdx = channelInfo->getSubProcessorIdx();
-			 int nInfoArrays = continuousInfo.size();
+			 int nInfoArrays = continuousChannels.size();
 			 bool found = false;
 			 for (int i = lastId; i < nInfoArrays; i++)
 			 {
-				 if (sourceId == continuousInfo[i].sourceId && sourceSubIdx == continuousInfo[i].sourceSubIdx)
+				 if (sourceId == continuousChannels.getReference(i)[0]->getSourceNodeID() && sourceSubIdx == continuousChannels.getReference(i)[0]->getSubProcessorIdx())
 				 {
 					 //A dataset for the current processor from the current source is already present
-					 writeChannelIndexes.set(recordedChan, continuousInfo[i].nChannels);
-					 continuousInfo.getReference(i).nChannels += 1;
+					 writeChannelIndexes.set(recordedChan, continuousChannels.getReference(i).size());
+					 continuousChannels.getReference(i).add(getDataChannel(realChan));
 					 datasetIndexes.set(recordedChan, i);
 					 found = true;
 					 break;
@@ -85,31 +84,26 @@
 			 }
 			 if (!found) //a new dataset must be created
 			 {
-				 NWBRecordingInfo recInfo;
-				 recInfo.bitVolts = channelInfo->getBitVolts();
-				 recInfo.nChannels = 1;
-				 recInfo.processorId = procInfo.processorId;
-				 recInfo.sampleRate = channelInfo->getSampleRate();
-				 recInfo.sourceName = "processor: " + channelInfo->getSourceName() + " (" + String(sourceId) + "." + String(sourceSubIdx) + ")";
-				 recInfo.sourceId = sourceId;
-				 recInfo.sourceSubIdx = sourceSubIdx;
-				 recInfo.spikeElectrodeName = " ";
-				 recInfo.nSamplesPerSpike = 0;
-				 continuousInfo.add(recInfo);
+				 ContinuousGroup newGroup;
+				 newGroup.add(getDataChannel(realChan));
+				 continuousChannels.add(newGroup);
 				 datasetIndexes.set(recordedChan, nInfoArrays);
 				 writeChannelIndexes.set(recordedChan, 0);
 			 }
 
 		 }
-		 lastId = continuousInfo.size();
+		 lastId = continuousChannels.size();
 	 }
+	 int nEvents = getNumRecordedEvents();
+	 for (int i = 0; i < nEvents; i++)
+		 eventChannels.add(getEventChannel(i));
 
 	 //open the file
-	 recordFile->open(getNumRecordedChannels() + continuousInfo.size()); //total channels + timestamp arrays, to create a big enough buffer
+	 recordFile->open(getNumRecordedChannels() + continuousChannels.size() + eventChannels.size() + spikeChannels.size()); //total channels + timestamp arrays, to create a big enough buffer
 
 	 //create the recording
-	 recordFile->startNewRecording(recordingNumber, continuousInfo, spikeInfo);
-	 
+	 recordFile->startNewRecording(recordingNumber, continuousChannels, eventChannels, spikeChannels);
+	
  }
 
  
@@ -126,38 +120,24 @@
  {
 	 resetChannels(true);
  }
+
  
  void NWBRecordEngine::resetChannels(bool resetSpikes)
  {
-	 //Called at various points, should reset everything.
-
-	 if (resetSpikes) //only clear this at actual reset, not when closing files.
-		spikeInfo.clear();
-	 continuousInfo.clear();
+	 if (resetSpikes)
+		 spikeChannels.clear();
+	 eventChannels.clear();
+	 continuousChannels.clear();
 	 datasetIndexes.clear();
 	 writeChannelIndexes.clear();
-	 scaledBuffer.malloc(MAX_BUFFER_SIZE);
-	 intBuffer.malloc(MAX_BUFFER_SIZE);
 	 tsBuffer.malloc(MAX_BUFFER_SIZE);
 	 bufferSize = MAX_BUFFER_SIZE;
  }
  
  void NWBRecordEngine::writeData(int writeChannel, int realChannel, const float* buffer, int size)
  {
-	 if (size > bufferSize) //Shouldn't happen, and if it happens it'll be slow, but better this than crashing. Will be reset on file close and reset.
-	 {
-		 std::cerr << "Write buffer overrun, resizing to" << size << std::endl;
-		 bufferSize = size;
-		 scaledBuffer.malloc(size);
-		 intBuffer.malloc(size);
-		 tsBuffer.malloc(size);
-	 }
 
-	 double multFactor = 1 / (float(0x7fff) * getDataChannel(realChannel)->getBitVolts());
-	 FloatVectorOperations::copyWithMultiply(scaledBuffer.getData(), buffer, multFactor, size);
-	 AudioDataConverters::convertFloatToInt16LE(scaledBuffer.getData(), intBuffer.getData(), size);
-
-	 recordFile->writeData(datasetIndexes[writeChannel], writeChannelIndexes[writeChannel], size, intBuffer.getData());
+	 recordFile->writeData(datasetIndexes[writeChannel], writeChannelIndexes[writeChannel], size, buffer, getDataChannel(realChannel)->getBitVolts());
 
 	 /* All channels in a dataset have the same number of samples and share timestamps. But since this method is called 
 		asynchronously, the timestamps might not be in sync during acquisition, so we chose a channel and write the
@@ -178,51 +158,27 @@
  
 void NWBRecordEngine::writeEvent(int eventIndex, const MidiMessage& event) 
 {
-	if (Event::getEventType(event) == EventChannel::TTL)
-	{
-		TTLEventPtr ttl = TTLEvent::deserializeFromMessage(event, getEventChannel(eventIndex));
-		recordFile->writeTTLEvent(ttl->getChannel(), ttl->getState() ? 1 : 0, ttl->getSourceID() , double(ttl->getTimestamp()) / getEventChannel(eventIndex)->getSampleRate());
-	}
-	else if (Event::getEventType(event) == EventChannel::TEXT)
-	{
-		TextEventPtr text = TextEvent::deserializeFromMessage(event, getEventChannel(eventIndex));
-		recordFile->writeMessage(text->getText().toUTF8(), double(text->getTimestamp()) / getEventChannel(eventIndex)->getSampleRate());
-	}
+	const EventChannel* channel = getEventChannel(eventIndex);
+	EventPtr eventStruct = Event::deserializeFromMessage(event, channel);
+
+	recordFile->writeEvent(eventIndex, channel, eventStruct);
 }
 
 void NWBRecordEngine::writeTimestampSyncText(uint16 sourceID, uint16 sourceIdx, int64 timestamp, float sourceSampleRate, String text)
 {
-	recordFile->writeMessage(text.toUTF8(), double(timestamp) / sourceSampleRate);
+	recordFile->writeTimestampSyncText(sourceID, timestamp, sourceSampleRate, text);
 }
 
 void NWBRecordEngine::addSpikeElectrode(int index,const  SpikeChannel* elec) 
 {
-	//Called during chain update by a processor that records spikes. Allows the RecordEngine to gather data about the electrode, which will usually
-	//be used in openfiles to be sent to startNewRecording so the electrode info is stored into the file.
-	NWBRecordingInfo info;
-	info.bitVolts = elec->getChannelBitVolts(0);
-	info.nChannels = elec->getNumChannels();
-	info.nSamplesPerSpike = elec->getTotalSamples();
-	info.processorId = elec->getCurrentNodeID();
-	info.sourceId = elec->getSourceNodeID();
-	info.sourceSubIdx = elec->getSubProcessorIdx();
-	info.sampleRate = elec->getSampleRate();
-	info.sourceName = elec->getSourceName() + " (" + String(info.sourceId) + "." + String(info.sourceSubIdx) + ")";
-	info.spikeElectrodeName = elec->getName();
-	spikeInfo.add(info);
+	spikeChannels.add(elec);
 }
+
 void NWBRecordEngine::writeSpike(int electrodeIndex, const SpikeEvent* spike) 
 {
 	const SpikeChannel* channel = getSpikeChannel(electrodeIndex);
 
-	int totalSamples = channel->getTotalSamples() * channel->getNumChannels();
-	double timestamp = double(spike->getTimestamp()) / channel->getSampleRate();
-
-	double multFactor = 1 / (float(0x7fff) * channel->getChannelBitVolts(0));
-	FloatVectorOperations::copyWithMultiply(scaledBuffer.getData(), spike->getDataPointer(), multFactor, totalSamples);
-	AudioDataConverters::convertFloatToInt16LE(scaledBuffer.getData(), intBuffer.getData(), totalSamples);
-
-	recordFile->writeSpike(electrodeIndex, intBuffer.getData(), timestamp);
+	recordFile->writeSpike(electrodeIndex, channel, spike);
 }
 
 RecordEngineManager* NWBRecordEngine::getEngineManager()
diff --git a/Source/Plugins/NWBFormat/NWBRecording.h b/Source/Plugins/NWBFormat/NWBRecording.h
index 58864e061acb9a09ff3a72b04e2816a4d36cf02a..e521a34c35dbb2a4627a318bce94c7bd6d33d534 100644
--- a/Source/Plugins/NWBFormat/NWBRecording.h
+++ b/Source/Plugins/NWBFormat/NWBRecording.h
@@ -49,17 +49,16 @@
 			
 		private:
 			void resetChannels(bool resetSpikes);
-			Array<NWBRecordingInfo> continuousInfo;
-			Array<NWBRecordingInfo> spikeInfo;
-
 			ScopedPointer<NWBFile> recordFile;
 			Array<int> datasetIndexes;
 			Array<int> writeChannelIndexes;
 
-			HeapBlock<float> scaledBuffer;
-			HeapBlock<int16> intBuffer;
+			Array<ContinuousGroup> continuousChannels;
+			Array<const EventChannel*> eventChannels;
+			Array<const SpikeChannel*> spikeChannels;
+
 			HeapBlock<double> tsBuffer;
-			int bufferSize;
+			size_t bufferSize;
 
 			String identifierText;
 			
diff --git a/Source/Processors/Channel/InfoObjects.cpp b/Source/Processors/Channel/InfoObjects.cpp
index fe6a1302b65a44c3c0b2c14daf136de8df47930d..c49d4b8923f15e113ef2c3cd05f69599bdd73f2c 100644
--- a/Source/Processors/Channel/InfoObjects.cpp
+++ b/Source/Processors/Channel/InfoObjects.cpp
@@ -42,6 +42,16 @@ unsigned int NodeInfoBase::getCurrentNodeID() const
 	return m_nodeID;
 }
 
+String NodeInfoBase::getCurrentNodeType() const
+{
+	return m_currentNodeType;
+}
+
+String NodeInfoBase::getCurrentNodeName() const
+{
+	return m_currentNodeName;
+}
+
 //History Object
 HistoryObject::~HistoryObject()
 {}
@@ -64,7 +74,8 @@ SourceProcessorInfo::SourceProcessorInfo(const GenericProcessor* source, uint16
 	:	m_sourceNodeID(source->getNodeId()),
 		m_sourceSubNodeIndex(subproc), 
 		m_sourceType(source->getName()),
-		m_sourceName(source->getName()) //TODO: fix those two when we have the ability to rename processors
+		m_sourceName(source->getName()), //TODO: fix those two when we have the ability to rename processors
+		m_sourceSubProcessorCount(source->getNumSubProcessors())
 {
 }
 
@@ -91,6 +102,11 @@ String SourceProcessorInfo::getSourceName() const
 	return m_sourceName;
 }
 
+uint16 SourceProcessorInfo::getSourceSubprocessorCount() const
+{
+	return m_sourceSubProcessorCount;
+}
+
 //NamedInfoObject
 NamedInfoObject::~NamedInfoObject()
 {}
@@ -110,7 +126,7 @@ void NamedInfoObject::setIdentifier(String identifier)
 	m_identifier = identifier;
 }
 
-String NamedInfoObject::getDescriptor() const
+String NamedInfoObject::getIdentifier() const
 {
 	return m_identifier;
 }
diff --git a/Source/Processors/Channel/InfoObjects.h b/Source/Processors/Channel/InfoObjects.h
index a9c44fd9f0a4dd3cf3e6cdcc9bc7bc34ccb5691f..a3e1679b52941ab288494aa98d7b47c58ca6248b 100644
--- a/Source/Processors/Channel/InfoObjects.h
+++ b/Source/Processors/Channel/InfoObjects.h
@@ -50,10 +50,16 @@ public:
     virtual ~NodeInfoBase();
 	/** Gets the ID of the processor which currently owns this copy of the info object */
 	unsigned int getCurrentNodeID() const;
+	/** Gets the type of the processor which currently owns this copy of the info object */
+	String getCurrentNodeType() const;
+	/** Gets the name of the processor which currently owns this copy of the info object */
+	String getCurrentNodeName() const;
 protected:
 	NodeInfoBase() = delete;
 	NodeInfoBase(uint16 id);
 	uint16 m_nodeID{ 0 };
+	String m_currentNodeType;
+	String m_currentNodeName;
 };
 
 /** This class allows creating a string with an historic of all the data a node has gone through */
@@ -92,13 +98,17 @@ public:
 	/** Gets the name of the processor which created this object */
 	String getSourceName() const;
 
+	/** Gets the number of subprocessors the source processor has.
+	Useful to determine if a processor has multiple subprocessors and label things accordingly*/
+	uint16 getSourceSubprocessorCount() const;
+ 
 private:
 	SourceProcessorInfo() = delete;
 	const uint16 m_sourceNodeID;
 	const uint16 m_sourceSubNodeIndex;
 	const String m_sourceType;
 	const String m_sourceName;
-
+	const uint16 m_sourceSubProcessorCount;
 };
 
 class PLUGIN_API NamedInfoObject
@@ -120,7 +130,7 @@ public:
 	/** Sets a machine-readable data identifier (eg.: sourcedata.continuous ) */
 	void setIdentifier(String identifier);
 
-	String getDescriptor() const;
+	String getIdentifier() const;
 protected:
 	NamedInfoObject();
 	virtual void setDefaultNameAndDescription() = 0;
diff --git a/Source/Processors/Channel/MetaData.cpp b/Source/Processors/Channel/MetaData.cpp
index 5945ebd9fd1092fc4190b1f8685ddcfa77c39c1f..5dca331398785c7bcdfb1643bddcd620919b5858 100644
--- a/Source/Processors/Channel/MetaData.cpp
+++ b/Source/Processors/Channel/MetaData.cpp
@@ -39,6 +39,8 @@ bool checkMetaDataType(MetaDataDescriptor::MetaDataTypes baseType)
 	case MetaDataDescriptor::UINT32: return std::is_same<uint32, T>::value;
 	case MetaDataDescriptor::INT64: return std::is_same<int64, T>::value;
 	case MetaDataDescriptor::UINT64: return std::is_same<uint64, T>::value;
+	case MetaDataDescriptor::FLOAT: return std::is_same<float, T>::value;
+	case MetaDataDescriptor::DOUBLE: return std::is_same<double, T>::value;
 	default: return false;
 	}
 }
@@ -162,7 +164,7 @@ size_t MetaDataValue::getDataSize() const
 
 void MetaDataValue::allocSpace()
 {
-	m_data.malloc(m_size);
+	m_data.calloc(m_size);
 }
 
 MetaDataValue::MetaDataValue(const MetaDataValue& v)
@@ -239,6 +241,19 @@ void MetaDataValue::getValue(T* data) const
 	memcpy(data, m_data.getData(), m_size);
 }
 
+//Using this version of the method in normal processor operation is not recommended
+//However it is useful for format-agnostic processes.
+template<>
+void MetaDataValue::getValue<void>(void* data) const
+{
+	memcpy(data, m_data.getData(), m_size);
+}
+
+const void* MetaDataValue::getRawValuePointer() const
+{
+	return m_data.getData();
+}
+
 template <typename T>
 void MetaDataValue::setValue(const Array<T>& data)
 {
@@ -335,7 +350,10 @@ void MetaDataEventObject::addEventMetaData(MetaDataDescriptor* desc)
 		return;
 	}
 	m_eventMetaDataDescriptorArray.add(desc);
-	m_totalSize += desc->getDataSize();
+	size_t size = desc->getDataSize();
+	m_totalSize += size;
+	if (m_maxSize < size)
+		m_maxSize = size;
 }
 
 void MetaDataEventObject::addEventMetaData(const MetaDataDescriptor& desc)
@@ -347,7 +365,10 @@ void MetaDataEventObject::addEventMetaData(const MetaDataDescriptor& desc)
 		return;
 	}
 	m_eventMetaDataDescriptorArray.add(new MetaDataDescriptor(desc));
-	m_totalSize += desc.getDataSize();
+	size_t size = desc.getDataSize();
+	m_totalSize += size;
+	if (m_maxSize < size)
+		m_maxSize = size;
 }
 
 size_t MetaDataEventObject::getTotalEventMetaDataSize() const
@@ -360,7 +381,7 @@ const MetaDataDescriptor* MetaDataEventObject::getEventMetaDataDescriptor(int in
 	return m_eventMetaDataDescriptorArray[index];
 }
 
-const int MetaDataEventObject::getEventMetaDataCount() const
+int MetaDataEventObject::getEventMetaDataCount() const
 {
 	return m_eventMetaDataDescriptorArray.size();
 }
@@ -377,16 +398,31 @@ int MetaDataEventObject::findEventMetaData(MetaDataDescriptor::MetaDataTypes typ
 	return -1;
 }
 
+size_t MetaDataEventObject::getMaxEventMetaDataSize() const
+{
+	return m_maxSize;
+}
+
 //MetaDataEvent
 MetaDataEvent::MetaDataEvent() {}
 
 MetaDataEvent::~MetaDataEvent() {}
 
+int MetaDataEvent::getMetadataValueCount() const
+{
+	return m_metaDataValues.size();
+}
+
+const MetaDataValue* MetaDataEvent::getMetaDataValue(int index) const
+{
+	return m_metaDataValues[index];
+}
+
 void MetaDataEvent::serializeMetaData(void* dstBuffer) const
 {
 	int metaDataSize = m_metaDataValues.size();
 	char* buffer = static_cast<char*>(dstBuffer);
-	int ptrIndex = 0;
+	size_t ptrIndex = 0;
 
 	for (int i = 0; i < metaDataSize; i++)
 	{
@@ -405,7 +441,7 @@ bool MetaDataEvent::deserializeMetaData(const MetaDataEventObject* info, const v
 	{
 		const MetaDataDescriptor* desc = info->getEventMetaDataDescriptor(i);
 		size_t dataSize = desc->getDataSize();
-		if ((memIndex + dataSize) < size) return false; //check for buffer boundaries
+		if ((memIndex + dataSize) > size) return false; //check for buffer boundaries
 		
 		metaData.add(new MetaDataValue(*desc, (static_cast<const char*>(srcBuffer) + memIndex)));
 		memIndex += dataSize;
@@ -495,6 +531,8 @@ template PLUGIN_API void MetaDataValue::getValue<uint64>(Array<uint64>&) const;
 template PLUGIN_API void MetaDataValue::getValue<float>(Array<float>&) const;
 template PLUGIN_API void MetaDataValue::getValue<double>(Array<double>&) const;
 
+template PLUGIN_API void MetaDataValue::getValue<void>(void*) const;
+
 //Helper function to compare identifier strings
 bool compareIdentifierStrings(const String& identifier, const String& compareWith)
 {
diff --git a/Source/Processors/Channel/MetaData.h b/Source/Processors/Channel/MetaData.h
index 0c799cd7653ba1648551444c0c8ee3f3de8b0a52..7ecbb0b164667dd86e86ef57eebf310a3cea54f8 100644
--- a/Source/Processors/Channel/MetaData.h
+++ b/Source/Processors/Channel/MetaData.h
@@ -149,6 +149,11 @@ public:
 	template <typename T>
 	void getValue(Array<T>& data) const;
 
+	/** It is generally not advised to use this method, which can, however, be of use in performance critical modules.
+	It is usually preferable to use the strongly typed copy getter methods, when speed is not an issue.
+	Keep in mind that any pointer returned by this will become invalid after the block execution.*/
+	const void* getRawValuePointer() const;
+
 private:
 	MetaDataValue() = delete;
 	void setValue(const void* data);
@@ -207,11 +212,14 @@ public:
 	const MetaDataDescriptor* getEventMetaDataDescriptor(int index) const;
 	int findEventMetaData(MetaDataDescriptor::MetaDataTypes type, unsigned int length, String identifier = String::empty) const;
 	size_t getTotalEventMetaDataSize() const;
-	const int getEventMetaDataCount() const;
+	int getEventMetaDataCount() const;
+	//gets the largest metadata size, which can be useful to reserve buffers in advance
+	size_t getMaxEventMetaDataSize() const;
 protected:
 	MetaDataDescriptorArray m_eventMetaDataDescriptorArray;
 	MetaDataEventObject();
 	size_t m_totalSize{ 0 };
+	size_t m_maxSize{ 0 };
 };
 
 //And the base from which event objects can hold their metadata before serializing
@@ -219,6 +227,8 @@ class PLUGIN_API MetaDataEvent
 {
 public:
     virtual ~MetaDataEvent();
+	int getMetadataValueCount() const;
+	const MetaDataValue* getMetaDataValue(int index) const;
 protected:
 	void serializeMetaData(void* dstBuffer) const;
 	bool deserializeMetaData(const MetaDataEventObject* info, const void* srcBuffer, int size);
diff --git a/Source/Processors/GenericProcessor/GenericProcessor.cpp b/Source/Processors/GenericProcessor/GenericProcessor.cpp
index b82fc42251808729dbce6bfde59354d385bd4b3e..b0f11fd1ea3f1ac4f200b4f4cdad0a055f86f7ec 100755
--- a/Source/Processors/GenericProcessor/GenericProcessor.cpp
+++ b/Source/Processors/GenericProcessor/GenericProcessor.cpp
@@ -333,19 +333,20 @@ void GenericProcessor::update()
             dataChannelArray.add (ch);
         }
 
-        for (int i = 0; i < sourceNode->eventChannelArray.size(); ++i)
-        {
-            EventChannel* sourceChan = sourceNode->eventChannelArray[i];
-            EventChannel* ch = new EventChannel (*sourceChan);
+		for (int i = 0; i < sourceNode->eventChannelArray.size(); ++i)
+		{
+			EventChannel* sourceChan = sourceNode->eventChannelArray[i];
+			EventChannel* ch = new EventChannel(*sourceChan);
 			ch->eventMetaDataLock = true;
-            eventChannelArray.add (ch);
-        }
+			eventChannelArray.add(ch);
+		}
 		for (int i = 0; i < sourceNode->spikeChannelArray.size(); ++i)
 		{
 			SpikeChannel* sourceChan = sourceNode->spikeChannelArray[i];
 			SpikeChannel* ch = new SpikeChannel(*sourceChan);
 			ch->eventMetaDataLock = true;
 			spikeChannelArray.add(ch);
+
 		}
 		for (int i = 0; i < sourceNode->configurationObjectArray.size(); ++i)
 		{
@@ -409,7 +410,11 @@ void GenericProcessor::updateChannelIndexes(bool updateNodeID)
 	{
 		DataChannel* channel = dataChannelArray[i];
 		if (updateNodeID)
+		{
 			channel->m_nodeID = nodeId;
+			channel->m_currentNodeName = getName();
+			channel->m_currentNodeType = getName(); //Fix when the ability to name individual processors is implemented
+		}
 		uint32 sourceID = getProcessorFullId(channel->getSourceNodeID(), channel->getSubProcessorIdx());
 		dataChannelMap[sourceID][channel->getSourceIndex()] = i;
 	}
@@ -417,7 +422,11 @@ void GenericProcessor::updateChannelIndexes(bool updateNodeID)
 	{
 		EventChannel* channel = eventChannelArray[i];
 		if (updateNodeID)
+		{
 			channel->m_nodeID = nodeId;
+			channel->m_currentNodeName = getName();
+			channel->m_currentNodeType = getName(); //Fix when the ability to name individual processors is implemented
+		}
 		uint32 sourceID = getProcessorFullId(channel->getSourceNodeID(), channel->getSubProcessorIdx());
 		eventChannelMap[sourceID][channel->getSourceIndex()] = i;
 	}
@@ -425,7 +434,11 @@ void GenericProcessor::updateChannelIndexes(bool updateNodeID)
 	{
 		SpikeChannel* channel = spikeChannelArray[i];
 		if (updateNodeID)
+		{
 			channel->m_nodeID = nodeId;
+			channel->m_currentNodeName = getName();
+			channel->m_currentNodeType = getName(); //Fix when the ability to name individual processors is implemented
+		}
 		uint32 sourceID = getProcessorFullId(channel->getSourceNodeID(), channel->getSubProcessorIdx());
 		spikeChannelMap[sourceID][channel->getSourceIndex()] = i;
 	}
diff --git a/Source/Processors/RecordNode/EngineConfigWindow.cpp b/Source/Processors/RecordNode/EngineConfigWindow.cpp
index 3882d27532e496d14d0800a1f28c45e01a7db07b..6fb06d7c12ae92d68ca98f87c3f2c4e7285efa9d 100644
--- a/Source/Processors/RecordNode/EngineConfigWindow.cpp
+++ b/Source/Processors/RecordNode/EngineConfigWindow.cpp
@@ -30,7 +30,7 @@ EngineParameterComponent::EngineParameterComponent(EngineParameter& param)
     {
         ToggleButton* but = new ToggleButton();
         but->setToggleState(param.boolParam.value,dontSendNotification);
-        but->setBounds(120,0,40,20);
+        but->setBounds(120,0,100,20);
         addAndMakeVisible(but);
         control = but;
     }
diff --git a/Source/Processors/RecordNode/EventQueue.h b/Source/Processors/RecordNode/EventQueue.h
index a83e6d45b0abe37fe9e8d0ba65909d6e56289df4..771bbc67ea22874692bd876064edea2550f88fe1 100644
--- a/Source/Processors/RecordNode/EventQueue.h
+++ b/Source/Processors/RecordNode/EventQueue.h
@@ -130,7 +130,8 @@ private:
 
 	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EventQueue);
 };
-
+//NOTE: Events are sent as midimessages while spikes as spike objects due to the difference on how they are passed to the record node.
+//Once the probe system is implemented, this will be normalized
 typedef EventQueue<MidiMessage> EventMsgQueue;
 typedef EventQueue<SpikeEvent> SpikeMsgQueue;
 typedef ReferenceCountedObjectPtr<AsyncEventMessage<MidiMessage>> EventMessagePtr;
diff --git a/Source/Processors/RecordNode/OriginalRecording.cpp b/Source/Processors/RecordNode/OriginalRecording.cpp
index fc5b8ac333d3edfe737f4de9e8d293803b0ac3e7..f3163358b07af7d90a3cea1e010a6430ca42b050 100644
--- a/Source/Processors/RecordNode/OriginalRecording.cpp
+++ b/Source/Processors/RecordNode/OriginalRecording.cpp
@@ -67,21 +67,6 @@ String OriginalRecording::getEngineID() const
     return "OPENEPHYS";
 }
 
-void OriginalRecording::registerProcessor(const GenericProcessor* proc)
-{
-	procIndex = 0;
-}
-
-void OriginalRecording::addDataChannel(int index, const DataChannel* chan)
-{
-    //Just populate the file array with null so we can address it by index afterwards
-    fileArray.add(nullptr);
-    blockIndex.add(0);
-    samplesSinceLastTimestamp.add(0);
-	originalChannelIndexes.add(procIndex);
-	procIndex++;
-}
-
 void OriginalRecording::addSpikeElectrode(int index, const SpikeChannel* elec)
 {
     spikeFileArray.add(nullptr);
@@ -109,16 +94,15 @@ void OriginalRecording::openFiles(File rootFolder, int experimentNumber, int rec
     openFile(rootFolder,getEventChannel(0), 0);
     openMessageFile(rootFolder);
 
-    for (int i = 0; i < fileArray.size(); i++)
-    {
-        if (getDataChannel(i)->getRecordState())
-        {
-            openFile(rootFolder,getDataChannel(i),i);
-            blockIndex.set(i,0);
-            samplesSinceLastTimestamp.set(i,0);
-        }
+	int nChannels = getNumRecordedChannels();
 
-    }
+	for (int i = 0; i < nChannels; i++)
+	{
+		const DataChannel* ch = getDataChannel(getRealChannel(i));
+		openFile(rootFolder, ch, getRealChannel(i));
+		blockIndex.add(0);
+		samplesSinceLastTimestamp.add(0);
+	}
     for (int i = 0; i < spikeFileArray.size(); i++)
     {
         openSpikeFile(rootFolder,getSpikeChannel(i),i);
@@ -184,7 +168,7 @@ void OriginalRecording::openFile(File rootFolder, const InfoObjectCommon* ch, in
         eventFile = chFile;
     else
     {
-        fileArray.set(channelIndex,chFile);
+        fileArray.add(chFile);
         if (ch->getCurrentNodeID() != lastProcId)
         {
             lastProcId = ch->getCurrentNodeID();
@@ -465,10 +449,7 @@ void OriginalRecording::writeData(int writeChannel, int realChannel, const float
 {
 	int samplesWritten = 0;
 
-	//int sourceNodeId = getChannel(realChannel)->sourceNodeId;
-
-	//TODO: optimize. Now we use realchannel, we should optimize the whole thing to only use recorded channels
-	samplesSinceLastTimestamp.set(realChannel, 0);
+	samplesSinceLastTimestamp.set(writeChannel, 0);
 
 	int nSamples = size;
 
@@ -476,7 +457,7 @@ void OriginalRecording::writeData(int writeChannel, int realChannel, const float
             {
                 int numSamplesToWrite = nSamples - samplesWritten;
 
-                if (blockIndex[realChannel] + numSamplesToWrite < BLOCK_LENGTH) // we still have space in this block
+				if (blockIndex[writeChannel] + numSamplesToWrite < BLOCK_LENGTH) // we still have space in this block
                 {
 
                     // write buffer to disk!
@@ -485,15 +466,15 @@ void OriginalRecording::writeData(int writeChannel, int realChannel, const float
                                           writeChannel);
 
                     //timestamp += numSamplesToWrite;
-                    samplesSinceLastTimestamp.set(realChannel, samplesSinceLastTimestamp[realChannel] + numSamplesToWrite);
-                    blockIndex.set(realChannel, blockIndex[realChannel] + numSamplesToWrite);
+					samplesSinceLastTimestamp.set(writeChannel, samplesSinceLastTimestamp[writeChannel] + numSamplesToWrite);
+					blockIndex.set(writeChannel, blockIndex[writeChannel] + numSamplesToWrite);
                     samplesWritten += numSamplesToWrite;
 
                 }
                 else   // there's not enough space left in this block for all remaining samples
                 {
 
-                    numSamplesToWrite = BLOCK_LENGTH - blockIndex[realChannel];
+					numSamplesToWrite = BLOCK_LENGTH - blockIndex[writeChannel];
 
                     // write buffer to disk!
                     writeContinuousBuffer(buffer + samplesWritten,
@@ -503,8 +484,8 @@ void OriginalRecording::writeData(int writeChannel, int realChannel, const float
                     // update our variables
                     samplesWritten += numSamplesToWrite;
                     //timestamp += numSamplesToWrite;
-                    samplesSinceLastTimestamp.set(realChannel, samplesSinceLastTimestamp[realChannel] + numSamplesToWrite);
-                    blockIndex.set(realChannel,0); // back to the beginning of the block
+					samplesSinceLastTimestamp.set(writeChannel, samplesSinceLastTimestamp[writeChannel] + numSamplesToWrite);
+					blockIndex.set(writeChannel, 0); // back to the beginning of the block
                 }
             }
 
@@ -513,13 +494,12 @@ void OriginalRecording::writeData(int writeChannel, int realChannel, const float
 
 void OriginalRecording::writeContinuousBuffer(const float* data, int nSamples, int writeChannel)
 {
-	int channel = getRealChannel(writeChannel);
     // check to see if the file exists
-    if (fileArray[channel] == nullptr)
+	if (fileArray[writeChannel] == nullptr)
         return;
 
     // scale the data back into the range of int16
-    float scaleFactor =  float(0x7fff) * getDataChannel(channel)->getBitVolts();
+    float scaleFactor =  float(0x7fff) * getDataChannel(getRealChannel(writeChannel))->getBitVolts();
 
     for (int n = 0; n < nSamples; n++)
     {
@@ -527,9 +507,9 @@ void OriginalRecording::writeContinuousBuffer(const float* data, int nSamples, i
     }
     AudioDataConverters::convertFloatToInt16BE(continuousDataFloatBuffer, continuousDataIntegerBuffer, nSamples);
 
-    if (blockIndex[channel] == 0)
+	if (blockIndex[writeChannel] == 0)
     {
-        writeTimestampAndSampleCount(fileArray[channel], writeChannel);
+		writeTimestampAndSampleCount(fileArray[writeChannel], writeChannel);
     }
 
     diskWriteLock.enter();
@@ -537,7 +517,7 @@ void OriginalRecording::writeContinuousBuffer(const float* data, int nSamples, i
     size_t count = fwrite(continuousDataIntegerBuffer, // ptr
                           2,                               // size of each element
                           nSamples,                        // count
-                          fileArray[channel]); // ptr to FILE object
+						  fileArray[writeChannel]); // ptr to FILE object
 
     //std::cout << channel << " : " << nSamples << " : " << count << std::endl;
 
@@ -546,9 +526,9 @@ void OriginalRecording::writeContinuousBuffer(const float* data, int nSamples, i
 
     diskWriteLock.exit();
 
-    if (blockIndex[channel] + nSamples == BLOCK_LENGTH)
+	if (blockIndex[writeChannel] + nSamples == BLOCK_LENGTH)
     {
-        writeRecordMarker(fileArray[channel]);
+		writeRecordMarker(fileArray[writeChannel]);
     }
 }
 
@@ -605,13 +585,13 @@ void OriginalRecording::closeFiles()
                 writeContinuousBuffer(zeroBuffer.getReadPointer(0), BLOCK_LENGTH - blockIndex[i], i);
                 diskWriteLock.enter();
                 fclose(fileArray[i]);
-                fileArray.set(i,nullptr);
                 diskWriteLock.exit();
             }
         }
-
-        blockIndex.set(i,0);
     }
+	fileArray.clear();
+	blockIndex.clear();
+	samplesSinceLastTimestamp.clear();
     for (int i = 0; i < spikeFileArray.size(); i++)
     {
         if (spikeFileArray[i] != nullptr)
diff --git a/Source/Processors/RecordNode/OriginalRecording.h b/Source/Processors/RecordNode/OriginalRecording.h
index e417a1b708a9010918753dd7f09917b679205dc5..3730992ec2d91d1e0aef513f8eedc5b6fb7849aa 100644
--- a/Source/Processors/RecordNode/OriginalRecording.h
+++ b/Source/Processors/RecordNode/OriginalRecording.h
@@ -50,8 +50,6 @@ public:
 	void closeFiles() override;
 	void writeData(int writeChannel, int realChannel, const float* buffer, int size) override;
 	void writeEvent(int eventIndex, const MidiMessage& event) override;
-	void registerProcessor(const GenericProcessor* proc) override;
-	void addDataChannel(int index, const DataChannel* chan) override;
 	void resetChannels() override;
 	void addSpikeElectrode(int index, const SpikeChannel* elec) override;
 	void writeSpike(int electrodeIndex, const SpikeEvent* spike) override;
diff --git a/Source/Processors/RecordNode/RecordEngine.cpp b/Source/Processors/RecordNode/RecordEngine.cpp
index ed88af8b1facf06141a6a8c4058fb4e900002340..6aaef305fd4b5b3db8118d256a01200f92536645 100644
--- a/Source/Processors/RecordNode/RecordEngine.cpp
+++ b/Source/Processors/RecordNode/RecordEngine.cpp
@@ -103,6 +103,11 @@ int RecordEngine::getNumRecordedChannels() const
     return channelMap.size();
 }
 
+int RecordEngine::getNumRecordedEvents() const
+{
+	return AccessClass::getProcessorGraph()->getRecordNode()->getTotalEventChannels();
+}
+
 void RecordEngine::registerSpikeSource (const GenericProcessor* processor) {}
 
 int RecordEngine::getNumRecordedProcessors() const
diff --git a/Source/Processors/RecordNode/RecordEngine.h b/Source/Processors/RecordNode/RecordEngine.h
index a87fa260f35704685923379b0cc6df697c8c1a4e..f6864ec06021f644be3c7c78aaa81274926f5f7b 100644
--- a/Source/Processors/RecordNode/RecordEngine.h
+++ b/Source/Processors/RecordNode/RecordEngine.h
@@ -156,6 +156,7 @@ protected:
     /** Gets the specified channel from the channel array stored in RecordNode */
     const DataChannel* getDataChannel (int index) const;
 
+	/** Gets the specified event channel from the channel array stored in RecordNode */
 	const EventChannel* getEventChannel(int index) const;
 
     /** Gets the specified channel group info structure from the array stored in RecordNode */
@@ -173,6 +174,12 @@ protected:
     /** Gets the number of recorded channels */
     int getNumRecordedChannels() const;
 
+	/** Gets the number of recorded event channels
+	 (right now all channels are recorded) */
+	int getNumRecordedEvents() const;
+
+	/** TODO: to fill when the probe system is implemented*/
+	//int getNumRecordedSpikes() const;
 
     /** Gets the number of processors being recorded
     */
diff --git a/Source/Processors/RecordNode/RecordNode.cpp b/Source/Processors/RecordNode/RecordNode.cpp
index 592f1cf8a782562a6ac1426f579a067c9085b21e..b0c04492bcc98b29eef9d9a1066a9f5d0201d578 100755
--- a/Source/Processors/RecordNode/RecordNode.cpp
+++ b/Source/Processors/RecordNode/RecordNode.cpp
@@ -159,8 +159,10 @@ void RecordNode::addInputChannel(const GenericProcessor* sourceNode, int chan)
 
         for (int n = 0; n < sourceNode->getTotalEventChannels(); n++)
         {
-
-            eventChannelArray.add(new EventChannel(*sourceNode->getEventChannel(n)));
+			const EventChannel* orig = sourceNode->getEventChannel(n);
+			//only add to the record node the events originating from this processor, to avoid duplicates
+			if (orig->getSourceNodeID() == sourceNode->getNodeId())
+				eventChannelArray.add(new EventChannel(*orig));
 
         }
 
diff --git a/open-ephys.jucer b/open-ephys.jucer
index 3c996776dbf473a246555534a308e89edb04460b..80a6aa56695f4153c7e2d28fcf20b8cf47f8d394 100644
--- a/open-ephys.jucer
+++ b/open-ephys.jucer
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<JUCERPROJECT id="ynSYIrr" name="open-ephys" projectType="guiapp" version="0.4.2"
+<JUCERPROJECT id="ynSYIrr" name="open-ephys" projectType="guiapp" version="0.4.2.1"
               juceLinkage="amalg_multi" buildVST="1" buildRTAS="0" buildAU="1"
               pluginName="Juce Project" pluginDesc="Juce Project" pluginManufacturer="yourcompany"
               pluginManufacturerCode="Manu" pluginCode="Plug" pluginChannelConfigs="{1, 1}, {2, 2}"
@@ -11,7 +11,7 @@
               companyName="Open Ephys" userNotes="The Open Ephys GUI was designed to provide a fast and flexible interface for acquiring, processing, and visualizing data from extracellular electrodes. See open-ephys.org for more information."
               includeBinaryInAppConfig="1">
   <EXPORTFORMATS>
-    <LINUX_MAKE targetFolder="Builds/Linux" vstFolder="" extraLinkerFlags="-ldl -lXext -lGLU -rdynamic -fPIC"
+    <LINUX_MAKE targetFolder="Builds/Linux" vstFolder="" extraLinkerFlags="-ldl -lXext -lGLU -rdynamic -fPIC -Wl,-rpath,'$$ORIGIN'"
                 extraCompilerFlags="-rdynamic -fvisibility=hidden" extraDefs=""
                 smallIcon="nFMauU" bigIcon="nFMauU" cppLanguageStandard="-std=c++11">
       <CONFIGURATIONS>