diff --git a/Builds/Linux/Makefile b/Builds/Linux/Makefile
index a45f74ab9a643ed11e3d69c19006bd64b5036d3a..b00bec1330aed6503cd834f272de0ad03f5d17e4 100644
--- a/Builds/Linux/Makefile
+++ b/Builds/Linux/Makefile
@@ -106,6 +106,8 @@ OBJECTS := \
   $(OBJDIR)/ParameterEditor_112258eb.o \
   $(OBJDIR)/Parameter_b3e5ac9e.o \
   $(OBJDIR)/ProcessorGraph_8c3a250a.o \
+  $(OBJDIR)/DataQueue_d6cc297a.o \
+  $(OBJDIR)/RecordThread_fb797372.o \
   $(OBJDIR)/EngineConfigWindow_4fd44ceb.o \
   $(OBJDIR)/OriginalRecording_d6dc3293.o \
   $(OBJDIR)/RecordEngine_97ef83aa.o \
@@ -444,6 +446,16 @@ $(OBJDIR)/ProcessorGraph_8c3a250a.o: ../../Source/Processors/ProcessorGraph/Proc
 	@echo "Compiling ProcessorGraph.cpp"
 	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
 
+$(OBJDIR)/DataQueue_d6cc297a.o: ../../Source/Processors/RecordNode/DataQueue.cpp
+	-@mkdir -p $(OBJDIR)
+	@echo "Compiling DataQueue.cpp"
+	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
+$(OBJDIR)/RecordThread_fb797372.o: ../../Source/Processors/RecordNode/RecordThread.cpp
+	-@mkdir -p $(OBJDIR)
+	@echo "Compiling RecordThread.cpp"
+	@$(CXX) $(CXXFLAGS) -o "$@" -c "$<"
+
 $(OBJDIR)/EngineConfigWindow_4fd44ceb.o: ../../Source/Processors/RecordNode/EngineConfigWindow.cpp
 	-@mkdir -p $(OBJDIR)
 	@echo "Compiling EngineConfigWindow.cpp"
diff --git a/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj b/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj
index ef8805846618a18d72d1b24facd7356ac8f0ae57..ca65fc7961e97d1afff5167acda3b4773d8e1287 100644
--- a/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/open-ephys.xcodeproj/project.pbxproj
@@ -76,6 +76,8 @@
 		F2586A2DCEF44961AEA247E8 = {isa = PBXBuildFile; fileRef = 934B37E2BECD69E6E27051F6; };
 		3E7939ABAA984EE8BFC8CEDD = {isa = PBXBuildFile; fileRef = 4F5D51C5F8174E3824EF8B42; };
 		BAC379C03C2E7995F2393EF5 = {isa = PBXBuildFile; fileRef = 4CB63EE1552BBFDEB1DADB0A; };
+		0326A368BA8F70C74A8A12A7 = {isa = PBXBuildFile; fileRef = 74E31DA11A4C1244B78A077A; };
+		F7E069E1FC1BB7EF856AA083 = {isa = PBXBuildFile; fileRef = 699B3251715DE04674E0E0C4; };
 		E1247DDF1C88D99691499E52 = {isa = PBXBuildFile; fileRef = 7DB22AC6407EEA88F3FFA16D; };
 		0A8D8C2D02858F0F08356EA9 = {isa = PBXBuildFile; fileRef = E39CC410838072043E3C30DC; };
 		AEDA8F23648EABF79215B566 = {isa = PBXBuildFile; fileRef = F716728550EBD8FA7B9CA7EF; };
@@ -148,6 +150,7 @@
 		06072EC6BCD3B7D8C17C2402 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioProcessor.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_processors/processors/juce_AudioProcessor.cpp"; sourceTree = "SOURCE_ROOT"; };
 		0618303B4E1BF577974A03FE = {isa = PBXFileReference; lastKnownFileType = file.icns; name = Icon.icns; path = Icon.icns; sourceTree = "SOURCE_ROOT"; };
 		0646A83E4EE738EE5D914DA6 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Visualizer.cpp; path = ../../Source/Processors/Visualization/Visualizer.cpp; sourceTree = "SOURCE_ROOT"; };
+		066A1CD777247BC8142A7DAA = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EventQueue.h; path = ../../Source/Processors/RecordNode/EventQueue.h; sourceTree = "SOURCE_ROOT"; };
 		078625CF5C083AD538D23401 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioCDReader.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_devices/audio_cd/juce_AudioCDReader.cpp"; sourceTree = "SOURCE_ROOT"; };
 		0790CCE2FCFDFA6944DFC402 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_PopupMenu.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/menus/juce_PopupMenu.cpp"; sourceTree = "SOURCE_ROOT"; };
 		07B84F46CF90D04BB6B673C5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Merger.cpp; path = ../../Source/Processors/Merger/Merger.cpp; sourceTree = "SOURCE_ROOT"; };
@@ -577,6 +580,7 @@
 		693E9C5C9A435F791921DAAE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioDeviceManager.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp"; sourceTree = "SOURCE_ROOT"; };
 		696F2DC49934E6F01A2DF9FE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_FileTreeComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_FileTreeComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
 		698B0EC670DA47934444381B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Network.cpp"; path = "../../JuceLibraryCode/modules/juce_core/native/juce_win32_Network.cpp"; sourceTree = "SOURCE_ROOT"; };
+		699B3251715DE04674E0E0C4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = RecordThread.cpp; path = ../../Source/Processors/RecordNode/RecordThread.cpp; sourceTree = "SOURCE_ROOT"; };
 		6A559D9595A54EF52BF0773A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Range.h"; path = "../../JuceLibraryCode/modules/juce_core/maths/juce_Range.h"; sourceTree = "SOURCE_ROOT"; };
 		6A63308EBE68478531604BA4 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_DirectoryContentsList.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_DirectoryContentsList.cpp"; sourceTree = "SOURCE_ROOT"; };
 		6ABF91320A2EB6D307091AEE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_CameraDevice.mm"; path = "../../JuceLibraryCode/modules/juce_video/native/juce_mac_CameraDevice.mm"; sourceTree = "SOURCE_ROOT"; };
@@ -624,12 +628,14 @@
 		74A81014471CC0EB0D5E6571 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ValueTree.cpp"; path = "../../JuceLibraryCode/modules/juce_data_structures/values/juce_ValueTree.cpp"; sourceTree = "SOURCE_ROOT"; };
 		74BAC33D6BC1D961F04DCC72 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Channel.h; path = ../../Source/Processors/Channel/Channel.h; sourceTree = "SOURCE_ROOT"; };
 		74DE857CEFA10BC49FF591DB = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Synthesiser.h"; path = "../../JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.h"; sourceTree = "SOURCE_ROOT"; };
+		74E31DA11A4C1244B78A077A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = DataQueue.cpp; path = ../../Source/Processors/RecordNode/DataQueue.cpp; sourceTree = "SOURCE_ROOT"; };
 		753B81CCB5A6B6929679E7B7 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Application.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/application/juce_Application.h"; sourceTree = "SOURCE_ROOT"; };
 		7555A13E69B99B1B6C7295FD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_InputStream.cpp"; path = "../../JuceLibraryCode/modules/juce_core/streams/juce_InputStream.cpp"; sourceTree = "SOURCE_ROOT"; };
 		75A4EEE127FAB86D65FF5F6E = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_RelativeCoordinatePositioner.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/positioning/juce_RelativeCoordinatePositioner.cpp"; sourceTree = "SOURCE_ROOT"; };
 		75E0C433EC27CFB712CD9F75 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_PluginListComponent.h"; path = "../../JuceLibraryCode/modules/juce_audio_processors/scanning/juce_PluginListComponent.h"; sourceTree = "SOURCE_ROOT"; };
 		75FCE8908DD9055F90E93716 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ResizableBorderComponent.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/layout/juce_ResizableBorderComponent.cpp"; sourceTree = "SOURCE_ROOT"; };
 		76140C0485FDDA98C3D98E2A = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_OldSchoolLookAndFeel.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_extra/lookandfeel/juce_OldSchoolLookAndFeel.cpp"; sourceTree = "SOURCE_ROOT"; };
+		762A0D03A828BA95B3B9C209 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RecordThread.h; path = ../../Source/Processors/RecordNode/RecordThread.h; sourceTree = "SOURCE_ROOT"; };
 		766923F74E30FF5D6B12E7CE = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawableComposite.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawableComposite.h"; sourceTree = "SOURCE_ROOT"; };
 		76E89CBE70BF8F2476B7AA34 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_SortedSet.h"; path = "../../JuceLibraryCode/modules/juce_core/containers/juce_SortedSet.h"; sourceTree = "SOURCE_ROOT"; };
 		7719FB81DDF23CF0164B131D = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BlowFish.h"; path = "../../JuceLibraryCode/modules/juce_cryptography/encryption/juce_BlowFish.h"; sourceTree = "SOURCE_ROOT"; };
@@ -823,6 +829,7 @@
 		9F845E950F19FEC4E6C88F91 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Typeface.h"; path = "../../JuceLibraryCode/modules/juce_graphics/fonts/juce_Typeface.h"; sourceTree = "SOURCE_ROOT"; };
 		9FC97A1CFD250F7215B4E397 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_AudioCDBurner.mm"; path = "../../JuceLibraryCode/modules/juce_audio_devices/native/juce_mac_AudioCDBurner.mm"; sourceTree = "SOURCE_ROOT"; };
 		9FDCF1E2B4651E58240400B9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TextEditor.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/widgets/juce_TextEditor.h"; sourceTree = "SOURCE_ROOT"; };
+		A010F4CC42989CB1E73A8A94 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DataQueue.h; path = ../../Source/Processors/RecordNode/DataQueue.h; sourceTree = "SOURCE_ROOT"; };
 		A0434BD0EE742DF9089E2750 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RHD2000Editor.h; path = ../../Source/Processors/DataThreads/RhythmNode/RHD2000Editor.h; sourceTree = "SOURCE_ROOT"; };
 		A0D768F1B92568344DAC9F0B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_win32_Fonts.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/native/juce_win32_Fonts.cpp"; sourceTree = "SOURCE_ROOT"; };
 		A15596CDCC27B86FC070D7FA = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Desktop.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/components/juce_Desktop.cpp"; sourceTree = "SOURCE_ROOT"; };
@@ -1151,27 +1158,27 @@
 		E7ACE8C1456403A574236451 = {isa = PBXFileReference; lastKnownFileType = file; name = "cpmono-bold-serialized"; path = "../../Resources/Fonts/cpmono-bold-serialized"; sourceTree = "SOURCE_ROOT"; };
 		E7EE416EF527C7506B499070 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BigInteger.h"; path = "../../JuceLibraryCode/modules/juce_core/maths/juce_BigInteger.h"; sourceTree = "SOURCE_ROOT"; };
 		E835BEB3C42E4B241804BE13 = {isa = PBXFileReference; lastKnownFileType = file; name = "cpmono-light-serialized"; path = "../../Resources/Fonts/cpmono-light-serialized"; sourceTree = "SOURCE_ROOT"; };
-		E8964C0BE264A55753BC6B7B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Midi.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.cpp"; sourceTree = "SOURCE_ROOT"; };
 		E8D51D470C9955D7D03D5469 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ChebyshevII.h; path = ../../Source/Processors/Dsp/ChebyshevII.h; sourceTree = "SOURCE_ROOT"; };
-		E91923510CB2280C3A3B9E9C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LocalisedStrings.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h"; sourceTree = "SOURCE_ROOT"; };
-		EA354D7D8E48D461415D52D8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_JPEGLoader.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp"; sourceTree = "SOURCE_ROOT"; };
+		E946426F95E0240683CB3337 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawablePath.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawablePath.h"; sourceTree = "SOURCE_ROOT"; };
 		EA9518CDEA7049C21D5CE2D5 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_Process.h"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_Process.h"; sourceTree = "SOURCE_ROOT"; };
 		EAB6A66678B122C578B16445 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_HighResolutionTimer.h"; path = "../../JuceLibraryCode/modules/juce_core/threads/juce_HighResolutionTimer.h"; sourceTree = "SOURCE_ROOT"; };
+		EAC262A83CD2BEA14542AE89 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringPool.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringPool.h"; sourceTree = "SOURCE_ROOT"; };
+		EAEA49B9394D802B79CA8164 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringPairArray.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.h"; sourceTree = "SOURCE_ROOT"; };
 		EF3F9AA8D70E1D4D55F13182 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_AudioThumbnail.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_utils/gui/juce_AudioThumbnail.cpp"; sourceTree = "SOURCE_ROOT"; };
 		F5A00ACFA3D76168F22F1205 = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		99E1BC08B886CFDD2CCFD462 = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "open-ephys.app"; sourceTree = "BUILT_PRODUCTS_DIR"; };
 		E39CC410838072043E3C30DC = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = OriginalRecording.cpp; path = ../../Source/Processors/RecordNode/OriginalRecording.cpp; sourceTree = "SOURCE_ROOT"; };
+		E8964C0BE264A55753BC6B7B = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_linux_Midi.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_devices/native/juce_linux_Midi.cpp"; sourceTree = "SOURCE_ROOT"; };
+		E91923510CB2280C3A3B9E9C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_LocalisedStrings.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_LocalisedStrings.h"; sourceTree = "SOURCE_ROOT"; };
 		E91A272EF06892937CB4B9CE = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_ComponentDragger.cpp"; path = "../../JuceLibraryCode/modules/juce_gui_basics/mouse/juce_ComponentDragger.cpp"; sourceTree = "SOURCE_ROOT"; };
 		E93BE115650B1CB80EACB841 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = EditorViewportButtons.h; path = ../../Source/UI/EditorViewportButtons.h; sourceTree = "SOURCE_ROOT"; };
-		E946426F95E0240683CB3337 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_DrawablePath.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/drawables/juce_DrawablePath.h"; sourceTree = "SOURCE_ROOT"; };
 		E97684DCE824DEDA6683C6CD = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_Synthesiser.cpp"; path = "../../JuceLibraryCode/modules/juce_audio_basics/synthesisers/juce_Synthesiser.cpp"; sourceTree = "SOURCE_ROOT"; };
 		EA2FC92CECD1EDA1F07DC59C = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_TooltipWindow.h"; path = "../../JuceLibraryCode/modules/juce_gui_basics/windows/juce_TooltipWindow.h"; sourceTree = "SOURCE_ROOT"; };
+		EA354D7D8E48D461415D52D8 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_JPEGLoader.cpp"; path = "../../JuceLibraryCode/modules/juce_graphics/image_formats/juce_JPEGLoader.cpp"; sourceTree = "SOURCE_ROOT"; };
 		EA73332E3D5AEC04ADDFBB2A = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_AudioDataConverters.h"; path = "../../JuceLibraryCode/modules/juce_audio_basics/buffers/juce_AudioDataConverters.h"; sourceTree = "SOURCE_ROOT"; };
 		EAB2319C7AA57E06A2247CDF = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_BorderSize.h"; path = "../../JuceLibraryCode/modules/juce_graphics/geometry/juce_BorderSize.h"; sourceTree = "SOURCE_ROOT"; };
 		EAB637B566FEBBDADA654262 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_VSTMidiEventList.h"; path = "../../JuceLibraryCode/modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h"; sourceTree = "SOURCE_ROOT"; };
-		EAC262A83CD2BEA14542AE89 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringPool.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringPool.h"; sourceTree = "SOURCE_ROOT"; };
 		EAC7A64301F0BF2C5E33A1F9 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = "juce_InterprocessConnectionServer.cpp"; path = "../../JuceLibraryCode/modules/juce_events/interprocess/juce_InterprocessConnectionServer.cpp"; sourceTree = "SOURCE_ROOT"; };
-		EAEA49B9394D802B79CA8164 = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "juce_StringPairArray.h"; path = "../../JuceLibraryCode/modules/juce_core/text/juce_StringPairArray.h"; sourceTree = "SOURCE_ROOT"; };
 		EB5F9A50EB53A57D6AE303C2 = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = "juce_mac_QuickTimeMovieComponent.mm"; path = "../../JuceLibraryCode/modules/juce_video/native/juce_mac_QuickTimeMovieComponent.mm"; sourceTree = "SOURCE_ROOT"; };
 		EBD8622EAEF10558809888B7 = {isa = PBXFileReference; lastKnownFileType = image.png; name = "RadioButtons_selected_over-01.png"; path = "../../Resources/Images/Icons/RadioButtons_selected_over-01.png"; sourceTree = "SOURCE_ROOT"; };
 		EC95A2CF4B33EA37DA5FC1AC = {isa = PBXFileReference; lastKnownFileType = file.ttf; name = nordic.ttf; path = ../../Resources/Fonts/nordic.ttf; sourceTree = "SOURCE_ROOT"; };
@@ -1467,6 +1474,11 @@
 					4CB63EE1552BBFDEB1DADB0A,
 					B695B24906116ADEFC9D9B5C, ); name = ProcessorGraph; sourceTree = "<group>"; };
 		0E7092A11A3C96E5ECA71CDA = {isa = PBXGroup; children = (
+					74E31DA11A4C1244B78A077A,
+					A010F4CC42989CB1E73A8A94,
+					066A1CD777247BC8142A7DAA,
+					699B3251715DE04674E0E0C4,
+					762A0D03A828BA95B3B9C209,
 					7DB22AC6407EEA88F3FFA16D,
 					398BF0B03B719107E6093F98,
 					E39CC410838072043E3C30DC,
@@ -2807,6 +2819,8 @@
 					F2586A2DCEF44961AEA247E8,
 					3E7939ABAA984EE8BFC8CEDD,
 					BAC379C03C2E7995F2393EF5,
+					0326A368BA8F70C74A8A12A7,
+					F7E069E1FC1BB7EF856AA083,
 					E1247DDF1C88D99691499E52,
 					0A8D8C2D02858F0F08356EA9,
 					AEDA8F23648EABF79215B566,
diff --git a/Builds/VisualStudio2012/open-ephys.vcxproj b/Builds/VisualStudio2012/open-ephys.vcxproj
index 36d5935abbe1ec78356b38e4a1cf3995cfcea13e..0c0301996c320dbea3b6c93fc7714c1c3f8c7a4e 100644
--- a/Builds/VisualStudio2012/open-ephys.vcxproj
+++ b/Builds/VisualStudio2012/open-ephys.vcxproj
@@ -310,6 +310,8 @@
     <ClCompile Include="..\..\Source\Processors\Parameter\ParameterEditor.cpp"/>
     <ClCompile Include="..\..\Source\Processors\Parameter\Parameter.cpp"/>
     <ClCompile Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.cpp"/>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\DataQueue.cpp"/>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\RecordThread.cpp"/>
     <ClCompile Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.cpp"/>
     <ClCompile Include="..\..\Source\Processors\RecordNode\OriginalRecording.cpp"/>
     <ClCompile Include="..\..\Source\Processors\RecordNode\RecordEngine.cpp"/>
@@ -1527,6 +1529,9 @@
     <ClInclude Include="..\..\Source\Processors\Parameter\ParameterEditor.h"/>
     <ClInclude Include="..\..\Source\Processors\Parameter\Parameter.h"/>
     <ClInclude Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.h"/>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\DataQueue.h"/>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\EventQueue.h"/>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\RecordThread.h"/>
     <ClInclude Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.h"/>
     <ClInclude Include="..\..\Source\Processors\RecordNode\OriginalRecording.h"/>
     <ClInclude Include="..\..\Source\Processors\RecordNode\RecordEngine.h"/>
diff --git a/Builds/VisualStudio2012/open-ephys.vcxproj.filters b/Builds/VisualStudio2012/open-ephys.vcxproj.filters
index cdfdb6dd81f05ae25b15b88d4cb1cd3c8c3afc4b..426497b4220dc8a3017291cc97f20dbd61b82d8b 100644
--- a/Builds/VisualStudio2012/open-ephys.vcxproj.filters
+++ b/Builds/VisualStudio2012/open-ephys.vcxproj.filters
@@ -571,6 +571,12 @@
     <ClCompile Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.cpp">
       <Filter>open-ephys\Source\Processors\ProcessorGraph</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\DataQueue.cpp">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\RecordThread.cpp">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.cpp">
       <Filter>open-ephys\Source\Processors\RecordNode</Filter>
     </ClCompile>
@@ -2079,6 +2085,15 @@
     <ClInclude Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.h">
       <Filter>open-ephys\Source\Processors\ProcessorGraph</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\DataQueue.h">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\EventQueue.h">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\RecordThread.h">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.h">
       <Filter>open-ephys\Source\Processors\RecordNode</Filter>
     </ClInclude>
diff --git a/Builds/VisualStudio2013/open-ephys.vcxproj b/Builds/VisualStudio2013/open-ephys.vcxproj
index 70f120980976b9870847b4261581d61db486c953..9f63c1204dbeb10b41b1d9e00f6323bd93882e75 100644
--- a/Builds/VisualStudio2013/open-ephys.vcxproj
+++ b/Builds/VisualStudio2013/open-ephys.vcxproj
@@ -314,6 +314,8 @@
     <ClCompile Include="..\..\Source\Processors\Parameter\ParameterEditor.cpp"/>
     <ClCompile Include="..\..\Source\Processors\Parameter\Parameter.cpp"/>
     <ClCompile Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.cpp"/>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\DataQueue.cpp"/>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\RecordThread.cpp"/>
     <ClCompile Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.cpp"/>
     <ClCompile Include="..\..\Source\Processors\RecordNode\OriginalRecording.cpp"/>
     <ClCompile Include="..\..\Source\Processors\RecordNode\RecordEngine.cpp"/>
@@ -1531,6 +1533,9 @@
     <ClInclude Include="..\..\Source\Processors\Parameter\ParameterEditor.h"/>
     <ClInclude Include="..\..\Source\Processors\Parameter\Parameter.h"/>
     <ClInclude Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.h"/>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\DataQueue.h"/>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\EventQueue.h"/>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\RecordThread.h"/>
     <ClInclude Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.h"/>
     <ClInclude Include="..\..\Source\Processors\RecordNode\OriginalRecording.h"/>
     <ClInclude Include="..\..\Source\Processors\RecordNode\RecordEngine.h"/>
diff --git a/Builds/VisualStudio2013/open-ephys.vcxproj.filters b/Builds/VisualStudio2013/open-ephys.vcxproj.filters
index 52b9b68af1e7f94f3e8ff975c632e42ebcd793ed..f8f2090e35b7ca5a7505fb05e4ad517e1e98feb9 100644
--- a/Builds/VisualStudio2013/open-ephys.vcxproj.filters
+++ b/Builds/VisualStudio2013/open-ephys.vcxproj.filters
@@ -571,6 +571,12 @@
     <ClCompile Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.cpp">
       <Filter>open-ephys\Source\Processors\ProcessorGraph</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\DataQueue.cpp">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\Source\Processors\RecordNode\RecordThread.cpp">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.cpp">
       <Filter>open-ephys\Source\Processors\RecordNode</Filter>
     </ClCompile>
@@ -2079,6 +2085,15 @@
     <ClInclude Include="..\..\Source\Processors\ProcessorGraph\ProcessorGraph.h">
       <Filter>open-ephys\Source\Processors\ProcessorGraph</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\DataQueue.h">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\EventQueue.h">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\Source\Processors\RecordNode\RecordThread.h">
+      <Filter>open-ephys\Source\Processors\RecordNode</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\Source\Processors\RecordNode\EngineConfigWindow.h">
       <Filter>open-ephys\Source\Processors\RecordNode</Filter>
     </ClInclude>
diff --git a/Source/CoreServices.cpp b/Source/CoreServices.cpp
index 84a668fd697378d7d4e042cf2d1ea5aef302b787..f17620830644cc9276486889f22a137a99c862ed 100644
--- a/Source/CoreServices.cpp
+++ b/Source/CoreServices.cpp
@@ -107,6 +107,16 @@ void setAppendTextToRecordingDir(String text)
     getControlPanel()->setAppendText(text);
 }
 
+String getSelectedRecordEngineId()
+{
+	return getControlPanel()->getSelectedRecordEngineId();
+}
+
+bool setSelectedRecordEngineId(String id)
+{
+	return getControlPanel()->setSelectedRecordEngineId(id);
+}
+
 namespace RecordNode
 {
 void createNewrecordingDir()
@@ -145,7 +155,7 @@ int addSpikeElectrode(SpikeRecordInfo* elec)
 }
 };
 
-PLUGIN_API const char* getApplicationResource(const char* name, int& size)
+const char* getApplicationResource(const char* name, int& size)
 {
 	return BinaryData::getNamedResource(name, size);
 }
diff --git a/Source/CoreServices.h b/Source/CoreServices.h
index 4b46d403afc7ba1d76aefeeecc221147d6487962..b8e254d4a6bdcd85e5e3001b685077b25d145614 100644
--- a/Source/CoreServices.h
+++ b/Source/CoreServices.h
@@ -78,6 +78,14 @@ PLUGIN_API void setPrependTextToRecordingDir(String text);
 /** Manually set the text to be appended to the recording directory */
 PLUGIN_API void setAppendTextToRecordingDir(String text);
 
+/** Gets the ID fo the selected Record Engine*/
+PLUGIN_API String getSelectedRecordEngineId();
+
+/** Sets a specific RecordEngine to be used based on its id. 
+Return true if there is an engine with the specified ID and it's possible to
+change the current engine or false otherwise. */
+PLUGIN_API bool setSelectedRecordEngineId(String id);
+
 namespace RecordNode
 {
 /** Forces creation of new directory on recording */
diff --git a/Source/Plugins/Headers/CoreServicesHeader.h b/Source/Plugins/Headers/CoreServicesHeader.h
new file mode 100644
index 0000000000000000000000000000000000000000..49871820b0fb990c587922671f3c341c6b0a977a
--- /dev/null
+++ b/Source/Plugins/Headers/CoreServicesHeader.h
@@ -0,0 +1,29 @@
+/*
+------------------------------------------------------------------
+
+This file is part of the Open Ephys GUI
+Copyright (C) 2013 Open Ephys
+
+------------------------------------------------------------------
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/*
+This file references the CoreServices namespace header, in case a plugin type that usually doesn't
+access this namespace (FileSource, for example) needs, as a particular case, use its functionality
+*/
+
+#include "../../CoreServices.h"
diff --git a/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.cpp b/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.cpp
index af9c7951489da38569facb3e9714fe33f05eef15..7a626fc82a617e2f2f48ceeb5898e987f07f5a23 100644
--- a/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.cpp
+++ b/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.cpp
@@ -22,14 +22,14 @@
 */
 #include <H5Cpp.h>
 #include "KwikFileSource.h"
-
+#include <CoreServicesHeader.h>
 
 
 using namespace H5;
 
 #define PROCESS_ERROR std::cerr << "KwikFilesource exception: " << error.getCDetailMsg() << std::endl
 
-KWIKFileSource::KWIKFileSource() : samplePos(0)
+KWIKFileSource::KWIKFileSource() : samplePos(0), skipRecordEngineCheck(false)
 {
 }
 
@@ -247,4 +247,32 @@ void KWIKFileSource::processChannelData(int16* inBuffer, float* outBuffer, int c
         *(outBuffer+i) = *(inBuffer+(n*i)+channel) * bitVolts;
     }
 
+}
+
+bool KWIKFileSource::isReady()
+{
+	//HDF5 is by default not thread-safe, so we must warn the user.
+	if ((!skipRecordEngineCheck) && (CoreServices::getSelectedRecordEngineId() == "KWIK"))
+	{
+		int res = AlertWindow::showYesNoCancelBox(AlertWindow::WarningIcon, "Record format conflict",
+			"Both the selected input file for the File Reader and the output file format for recording use the HDF5 library.\n"
+			"This library is, by default, not thread safe, so running both at the same time might cause unexpected crashes (chances increase with signal complexity and number of recorded channels).\n\n"
+			"If you have a custom-built hdf5 library with the thread safe features turned on, you can safely continue, but performance will be reduced.\n"
+			"More information on:\n"
+			"https://www.hdfgroup.org/HDF5/doc/TechNotes/ThreadSafeLibrary.html\n"
+			"https://www.hdfgroup.org/hdf5-quest.html\n\n"
+			"Do you want to continue acquisition?", "Yes", "Yes and don't ask again", "No");
+		switch (res)
+		{
+		case 2:
+			skipRecordEngineCheck = true;
+		case 1:
+			return true;
+			break;
+		default:
+			return false;
+		}
+	}
+	else
+		return true;
 }
\ No newline at end of file
diff --git a/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.h b/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.h
index ba92857e831e7ccb2c86d0b6f1461311b1e665f1..7bacf4964b506f484270b414252f1be35bb6cb1e 100644
--- a/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.h
+++ b/Source/Plugins/KWIKFormat/FileSource/KwikFileSource.h
@@ -43,20 +43,23 @@ public:
     KWIKFileSource();
     ~KWIKFileSource();
 
-    int readData(int16* buffer, int nSamples);
+    int readData(int16* buffer, int nSamples) override;
 
-    void seekTo(int64 sample);
+    void seekTo(int64 sample) override;
 
-    void processChannelData(int16* inBuffer, float* outBuffer, int channel, int64 numSamples);
+    void processChannelData(int16* inBuffer, float* outBuffer, int channel, int64 numSamples) override;
+
+	bool isReady() override;
 
 private:
     ScopedPointer<H5::H5File> sourceFile;
     ScopedPointer<H5::DataSet> dataSet;
-    bool Open(File file);
-    void fillRecordInfo();
-    void updateActiveRecord();
+    bool Open(File file) override;
+    void fillRecordInfo() override;
+    void updateActiveRecord() override;
     int64 samplePos;
     Array<int> availableDataSets;
+	bool skipRecordEngineCheck;
 };
 
 
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.cpp b/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.cpp
index 46ac97f76d04f2eaeeb361938bbab2939d72830a..31eabc8f4b6afd674a7185407d7e156bb2d4c9ec 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.cpp
+++ b/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.cpp
@@ -25,7 +25,7 @@
 #include "HDF5FileFormat.h"
 
 #ifndef CHUNK_XSIZE
-#define CHUNK_XSIZE 640
+#define CHUNK_XSIZE 2048
 #endif
 
 #ifndef EVENT_CHUNK_SIZE
@@ -97,7 +97,7 @@ int HDF5FileBase::open(bool newfile, int nChans)
 		FileAccPropList props = FileAccPropList::DEFAULT;
 		if (nChans > 0)
 		{
-			props.setCache(0, 809, 8 * 2 * 640 * nChans, 1);
+			props.setCache(0, 809, 8 * 2 * CHUNK_XSIZE * nChans, 1);
 			//std::cout << "opening HDF5 " << getFileName() << " with nchans: " << nChans << std::endl;
 		}
 
@@ -506,6 +506,8 @@ HDF5RecordingData::HDF5RecordingData(DataSet* data)
 
 HDF5RecordingData::~HDF5RecordingData()
 {
+	//Safety
+	dSet->flush(H5F_SCOPE_GLOBAL);
 }
 int HDF5RecordingData::writeDataBlock(int xDataSize, HDF5FileBase::DataTypes type, void* data)
 {
@@ -712,6 +714,15 @@ void KWDFile::writeRowData(int16* data, int nSamples)
     curChan++;
 }
 
+void KWDFile::writeRowData(int16* data, int nSamples, int channel)
+{
+	if (channel >= 0 && channel < nChannels)
+	{
+		CHECK_ERROR(recdata->writeDataRow(channel, nSamples, I16, data));
+		curChan = channel;
+	}
+}
+
 //KWE File
 
 KWEFile::KWEFile(String basename) : HDF5FileBase()
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.h b/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.h
index 1be0343c6c3307ad7567a11c7555cbef9656a5d7..ca0f190f349f0ebfd422f8d91bf002220bd35095 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.h
+++ b/Source/Plugins/KWIKFormat/RecordEngine/HDF5FileFormat.h
@@ -127,6 +127,7 @@ public:
     void stopRecording();
     void writeBlockData(int16* data, int nSamples);
     void writeRowData(int16* data, int nSamples);
+	void writeRowData(int16* data, int nSamples, int channel);
     String getFileName();
 
 protected:
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp b/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp
index e3b415a5697b9ba7528ae1a0b35b0e951cece675..3806adcccf3df29f69ba1aaad7813d1c92ca7319 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp
+++ b/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.cpp
@@ -47,10 +47,12 @@ String HDF5Recording::getEngineID()
 //     this->timestamp = timestamp;
 // }
 
-void HDF5Recording::registerProcessor(GenericProcessor* proc)
+void HDF5Recording::registerProcessor(const GenericProcessor* proc)
 {
     HDF5RecordingInfo* info = new HDF5RecordingInfo();
-    info->sample_rate = proc->getSampleRate();
+	//This is a VERY BAD thig to do. temporary only until we fix const-correctness on GenericEditor methods
+	//(which implies modifying all the plugins and processors)
+    info->sample_rate = const_cast<GenericProcessor*>(proc)->getSampleRate();
     info->bit_depth = 16;
     info->multiSample = false;
     infoArray.add(info);
@@ -70,11 +72,12 @@ void HDF5Recording::resetChannels()
     sampleRatesArray.clear();
     processorMap.clear();
     infoArray.clear();
+	recordedChanToKWDChan.clear();
     if (spikesFile)
         spikesFile->resetChannels();
 }
 
-void HDF5Recording::addChannel(int index, Channel* chan)
+void HDF5Recording::addChannel(int index,const Channel* chan)
 {
     processorMap.add(processorIndex);
 }
@@ -94,15 +97,40 @@ void HDF5Recording::openFiles(File rootFolder, int experimentNumber, int recordi
     //Let's just put the first processor (usually the source node) on the KWIK for now
     infoArray[0]->name = String("Open Ephys Recording #") + String(recordingNumber);
 
-    if (hasAcquired)
+   /* if (hasAcquired)
         infoArray[0]->start_time = (*timestamps)[getChannel(0)->sourceNodeId]; //(*timestamps).begin()->first;
     else
-        infoArray[0]->start_time = 0;
+        infoArray[0]->start_time = 0;*/
+	infoArray[0]->start_time = getTimestamp(0);
 
     infoArray[0]->start_sample = 0;
     eventFile->startNewRecording(recordingNumber,infoArray[0]);
 
     //KWD files
+	recordedChanToKWDChan.clear();
+	Array<int> processorRecPos;
+	processorRecPos.insertMultiple(0, 0, fileArray.size());
+	for (int i = 0; i < getNumRecordedChannels(); i++)
+	{
+		int index = processorMap[getRealChannel(i)];
+		if (!fileArray[index]->isOpen())
+		{
+			fileArray[index]->initFile(getChannel(getRealChannel(i))->nodeId, basepath);
+			infoArray[index]->start_time = getTimestamp(i);
+		}
+
+		channelsPerProcessor.set(index, channelsPerProcessor[index] + 1);
+		bitVoltsArray[index]->add(getChannel(getRealChannel(i))->bitVolts);
+		sampleRatesArray[index]->add(getChannel(getRealChannel(i))->sampleRate);
+		if (getChannel(getRealChannel(i))->sampleRate != infoArray[index]->sample_rate)
+		{
+			infoArray[index]->multiSample = true;
+		}
+		int procPos = processorRecPos[index];
+		recordedChanToKWDChan.add(procPos);
+		processorRecPos.set(index, procPos+1);
+	} 
+#if 0
     for (int i = 0; i < processorMap.size(); i++)
     {
         int index = processorMap[i];
@@ -125,6 +153,7 @@ void HDF5Recording::openFiles(File rootFolder, int experimentNumber, int recordi
             }
         }
     }
+#endif
     for (int i = 0; i < fileArray.size(); i++)
     {
 		if ((!fileArray[i]->isOpen()) && (fileArray[i]->isReadyToOpen()))
@@ -169,42 +198,32 @@ void HDF5Recording::closeFiles()
     }
 }
 
-void HDF5Recording::writeData(AudioSampleBuffer& buffer)
+void HDF5Recording::writeData(int writeChannel, int realChannel, const float* buffer, int size)
 {
 //	int64 t1 = Time::getHighResolutionTicks();
-    for (int i = 0; i < buffer.getNumChannels(); i++)
-    {
-        if (getChannel(i)->getRecordState())
-        {
-
-            int sourceNodeId = getChannel(i)->sourceNodeId;
-            int nSamples = (*numSamples)[sourceNodeId];
-
-            double multFactor = 1/(float(0x7fff) * getChannel(i)->bitVolts);
-            int index = processorMap[getChannel(i)->recordIndex];
-            FloatVectorOperations::copyWithMultiply(scaledBuffer,buffer.getReadPointer(i,0),multFactor,nSamples);
-            AudioDataConverters::convertFloatToInt16LE(scaledBuffer,intBuffer,nSamples);
-            fileArray[index]->writeRowData(intBuffer,nSamples);
-        }
-    }
+	double multFactor = 1 / (float(0x7fff) * getChannel(realChannel)->bitVolts);
+	int index = processorMap[getChannel(realChannel)->recordIndex];
+	FloatVectorOperations::copyWithMultiply(scaledBuffer, buffer, multFactor, size);
+	AudioDataConverters::convertFloatToInt16LE(scaledBuffer, intBuffer, size);
+	fileArray[index]->writeRowData(intBuffer, size, recordedChanToKWDChan[writeChannel]);
 //	int64 t2 = Time::getHighResolutionTicks();
 //	std::cout << "record time: " << float(t2 - t1) / float(Time::getHighResolutionTicksPerSecond()) << std::endl;
 }
 
-void HDF5Recording::writeEvent(int eventType, MidiMessage& event, int samplePosition)
+void HDF5Recording::writeEvent(int eventType, const MidiMessage& event, int64 timestamp)
 {
     const uint8* dataptr = event.getRawData();
     if (eventType == GenericProcessor::TTL)
-        eventFile->writeEvent(0,*(dataptr+2),*(dataptr+1),(void*)(dataptr+3),(*timestamps)[*(dataptr+1)]+samplePosition);
+        eventFile->writeEvent(0,*(dataptr+2),*(dataptr+1),(void*)(dataptr+3),timestamp);
     else if (eventType == GenericProcessor::MESSAGE)
-        eventFile->writeEvent(1,*(dataptr+2),*(dataptr+1),(void*)(dataptr+6),(*timestamps)[*(dataptr+1)]+samplePosition);
+        eventFile->writeEvent(1,*(dataptr+2),*(dataptr+1),(void*)(dataptr+6),timestamp);
 }
 
-void HDF5Recording::addSpikeElectrode(int index, SpikeRecordInfo* elec)
+void HDF5Recording::addSpikeElectrode(int index, const SpikeRecordInfo* elec)
 {
     spikesFile->addChannelGroup(elec->numChannels);
 }
-void HDF5Recording::writeSpike(const SpikeObject& spike, int electrodeIndex)
+void HDF5Recording::writeSpike(int electrodeIndex, const SpikeObject& spike, int64 /*timestamp*/)
 {
     spikesFile->writeSpike(electrodeIndex,spike.nSamples,spike.data,spike.timestamp);
 }
diff --git a/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.h b/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.h
index dc27f26ff37934a868f8f37b0ea677da827410ea..a40f5f1e903885975d74fe3d9cf878951e473562 100644
--- a/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.h
+++ b/Source/Plugins/KWIKFormat/RecordEngine/HDF5Recording.h
@@ -33,17 +33,16 @@ public:
     HDF5Recording();
     ~HDF5Recording();
     String getEngineID();
-    void openFiles(File rootFolder, int experimentNumber, int recordingNumber);
-    void closeFiles();
-    void writeData(AudioSampleBuffer& buffer);
-    void writeEvent(int eventType, MidiMessage& event, int samplePosition);
-    void addChannel(int index, Channel* chan);
-    void addSpikeElectrode(int index, SpikeRecordInfo* elec);
-    void writeSpike(const SpikeObject& spike, int electrodeIndex);
-    void registerProcessor(GenericProcessor* processor);
-    void resetChannels();
-    //oid updateTimeStamp(int64 timestamp);
-    void startAcquisition();
+    void openFiles(File rootFolder, int experimentNumber, int recordingNumber) override;
+	void closeFiles() override;
+	void writeData(int writeChannel, int realChannel, const float* buffer, int size) override;
+	void writeEvent(int eventType, const MidiMessage& event, int64 timestamp) override;
+	void addChannel(int index, const Channel* chan) override;
+	void addSpikeElectrode(int index,const  SpikeRecordInfo* elec) override;
+	void writeSpike(int electrodeIndex, const SpikeObject& spike, int64 timestamp) override;
+	void registerProcessor(const GenericProcessor* processor) override;
+	void resetChannels() override;
+	void startAcquisition() override;
 
     static RecordEngineManager* getEngineManager();
 private:
@@ -52,6 +51,7 @@ private:
 
     Array<int> processorMap;
 	Array<int> channelsPerProcessor;
+	Array<int> recordedChanToKWDChan;
     OwnedArray<Array<float>> bitVoltsArray;
     OwnedArray<Array<float>> sampleRatesArray;
     OwnedArray<KWDFile> fileArray;
diff --git a/Source/Processors/FileReader/FileReader.cpp b/Source/Processors/FileReader/FileReader.cpp
index 727c27de4c9b0248dca04fe01b61c153a4db3c54..e19275f84e9361f47dbbb20d9668bb3c51208e19 100644
--- a/Source/Processors/FileReader/FileReader.cpp
+++ b/Source/Processors/FileReader/FileReader.cpp
@@ -80,7 +80,7 @@ bool FileReader::isReady() /* const */
     }
     else
     {
-        return true;
+        return input->isReady();
     }
 }
 
diff --git a/Source/Processors/FileReader/FileSource.cpp b/Source/Processors/FileReader/FileSource.cpp
index e506976a80b1b0def90e488699df0b0f04e47678..7657f27c7375096577636a4e3952e4463d65bd52 100644
--- a/Source/Processors/FileReader/FileSource.cpp
+++ b/Source/Processors/FileReader/FileSource.cpp
@@ -140,3 +140,8 @@ bool FileSource::OpenFile (File file)
 
     return fileOpened;
 }
+
+bool FileSource::isReady()
+{
+	return true;
+}
diff --git a/Source/Processors/FileReader/FileSource.h b/Source/Processors/FileReader/FileSource.h
index 43871a43ca81e363a2623c086ee363ae935ef6c8..68c6c6a07f40a208d1b879ef439eb5647fc49e15 100644
--- a/Source/Processors/FileReader/FileSource.h
+++ b/Source/Processors/FileReader/FileSource.h
@@ -67,6 +67,7 @@ public:
     virtual void processChannelData (int16* inBuffer, float* outBuffer, int channel, int64 numSamples) = 0;
     virtual void seekTo (int64 sample) = 0;
 
+	virtual bool isReady();
 
 protected:
     struct RecordInfo
diff --git a/Source/Processors/RecordNode/DataQueue.cpp b/Source/Processors/RecordNode/DataQueue.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4a1f4b0cf5d2c520dacaa8a5fc95897cc0491512
--- /dev/null
+++ b/Source/Processors/RecordNode/DataQueue.cpp
@@ -0,0 +1,218 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "../../../JuceLibraryCode/JuceHeader.h"
+#include "DataQueue.h"
+
+DataQueue::DataQueue(int blockSize, int nBlocks) :
+m_blockSize(blockSize),
+m_numBlocks(nBlocks),
+m_maxSize(blockSize*nBlocks),
+m_readInProgress(false),
+m_numChans(0),
+m_buffer(0, blockSize*nBlocks)
+{}
+
+DataQueue::~DataQueue()
+{}
+
+void DataQueue::setChannels(int nChans)
+{
+	if (m_readInProgress)
+		return;
+
+	m_fifos.clear();
+	m_readSamples.clear();
+	m_numChans = nChans;
+	m_timestamps.clear();
+	m_lastReadTimestamps.clear();
+
+	for (int i = 0; i < nChans; ++i)
+	{
+		m_fifos.add(new AbstractFifo(m_maxSize));
+		m_readSamples.add(0);
+		m_timestamps.add(new Array<int64>());
+		m_timestamps.getLast()->resize(m_numBlocks);
+		m_lastReadTimestamps.add(0);
+	}
+	m_buffer.setSize(nChans, m_maxSize);
+}
+
+void DataQueue::resize(int nBlocks)
+{
+	if (m_readInProgress)
+		return;
+	
+	int size = m_blockSize*nBlocks;
+	m_maxSize = size;
+	m_numBlocks = nBlocks;
+
+	for (int i = 0; i < m_numChans; ++i)
+	{
+		m_fifos[i]->setTotalSize(size);
+		m_fifos[i]->reset();
+		m_readSamples.set(i, 0);
+		m_timestamps[i]->resize(nBlocks);
+		m_lastReadTimestamps.set(i, 0);
+	}
+	m_buffer.setSize(m_numChans, size);
+}
+
+void DataQueue::fillTimestamps(int channel, int index, int size, int64 timestamp)
+{
+	//Search for the next block start.
+	int blockMod = index % m_blockSize;
+	int blockIdx = index / m_blockSize;
+	int64 startTimestamp;
+	int blockStartPos;
+
+	if (blockMod == 0) //block starts here
+	{
+		startTimestamp = timestamp;
+		blockStartPos = index;
+	}
+	else //we're in the middle of a block, correct to jump to the start of the next-
+	{
+		startTimestamp = timestamp + (m_blockSize - blockMod);
+		blockStartPos = index + (m_blockSize - blockMod);
+		blockIdx++;
+	}
+
+	//check that the block is in range
+	for (int i = 0; i < size; i += m_blockSize)
+	{
+		if ((blockStartPos + i) < (index + size))
+		{
+			int64 ts = startTimestamp + (i*m_blockSize);
+			m_timestamps[channel]->set(blockIdx, ts);
+		}
+
+	}
+}
+
+void DataQueue::writeChannel(const AudioSampleBuffer& buffer, int channel, int sourceChannel, int nSamples, int64 timestamp)
+{
+	int index1, size1, index2, size2;
+	m_fifos[channel]->prepareToWrite(nSamples, index1, size1, index2, size2);
+	if ((size1 + size2) < nSamples)
+	{ //TODO: turn this into a proper notification. Probably returning a bool.
+		std::cerr << "Recording Data Queue Overflow" << std::endl;
+	}
+	m_buffer.copyFrom(channel,
+		index1,
+		buffer,
+		sourceChannel,
+		0,
+		size1);
+	
+	fillTimestamps(channel, index1, size1, timestamp);
+	
+	if (size2 > 0)
+	{
+		m_buffer.copyFrom(channel,
+			index2,
+			buffer,
+			sourceChannel,
+			size1,
+			size2);
+
+		fillTimestamps(channel, index2, size2, timestamp + size1);
+	}
+	m_fifos[channel]->finishedWrite(size1 + size2);
+}
+
+/* 
+We could copy the internal circular buffer to an external one, as DataBuffer does. This class
+is, however, intended for disk writing, which is one of the most CPU-critical systems. Just
+allowing the record subsytem to access the internal buffer is way faster, altough it has to be
+done with special care and manually finish the read process.
+*/
+
+const AudioSampleBuffer& DataQueue::getAudioBufferReference() const
+{
+	return m_buffer;
+}
+
+bool DataQueue::startRead(Array<CircularBufferIndexes>& indexes, Array<int64>& timestamps, int nMax)
+{
+	//This should never happen, but it never hurts to be on the safe side.
+	if (m_readInProgress)
+		return false;
+
+	m_readInProgress = true;
+	indexes.clear(); //Just in case it's not empty already
+	timestamps.clear();
+
+	for (int chan = 0; chan < m_numChans; ++chan)
+	{
+		CircularBufferIndexes idx;
+		int readyToRead = m_fifos[chan]->getNumReady();
+		int samplesToRead = ((readyToRead > nMax) && (nMax > 0)) ? nMax : readyToRead;
+
+		m_fifos[chan]->prepareToRead(samplesToRead, idx.index1, idx.size1, idx.index2, idx.size2);
+		indexes.add(idx);
+		m_readSamples.set(chan, idx.size1 + idx.size2);
+		
+		int blockMod = idx.index1 % m_blockSize;
+		int blockDiff = (blockMod == 0) ? 0 : (m_blockSize - blockMod);
+
+		//If the next timestamp block is within the data we're reading, include the translated timestamp in the output
+		if (blockDiff < (idx.size1 + idx.size2))
+		{
+			int blockIdx = ((idx.index1 + blockDiff) / m_blockSize) % m_numBlocks;
+			int64 ts = m_timestamps[chan]->getUnchecked(blockIdx) - blockDiff;
+			timestamps.add(ts);
+			//update to the end of the block
+			m_lastReadTimestamps.set(chan, ts+ idx.size1 + idx.size2);
+		}
+		//If not, copy the last sent again 
+		else
+		{
+			int64 ts = m_lastReadTimestamps[chan];
+			timestamps.add(ts);
+			m_lastReadTimestamps.set(chan, ts + idx.size1 + idx.size2);
+		}
+	}
+	return true;
+}
+
+void DataQueue::stopRead()
+{
+	if (!m_readInProgress)
+		return;
+
+	for (int i = 0; i < m_numChans; ++i)
+	{
+		m_fifos[i]->finishedRead(m_readSamples[i]);
+		m_readSamples.set(i, 0);
+	}
+	m_readInProgress = false;
+}
+
+void DataQueue::getTimestampsForBlock(int idx, Array<int64>& timestamps) const
+{
+	timestamps.clear();
+	for (int chan = 0; chan < m_numChans; ++chan)
+	{
+		timestamps.add((*m_timestamps[chan])[idx]);
+	}
+}
\ No newline at end of file
diff --git a/Source/Processors/RecordNode/DataQueue.h b/Source/Processors/RecordNode/DataQueue.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d52d5fc22998157f3bbadf75bc1b6dc93852783
--- /dev/null
+++ b/Source/Processors/RecordNode/DataQueue.h
@@ -0,0 +1,73 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DATAQUEUE_H_INCLUDED
+#define DATAQUEUE_H_INCLUDED
+
+#include "../../../JuceLibraryCode/JuceHeader.h"
+
+struct CircularBufferIndexes
+{
+	int index1;
+	int size1;
+	int index2;
+	int size2;
+};
+
+class DataQueue
+{
+public:
+	DataQueue(int blockSize, int nBlocks);
+	~DataQueue();
+	void setChannels(int nChans);
+	void resize(int nBlocks);
+	void getTimestampsForBlock(int idx, Array<int64>& timestamps) const;
+
+	//Only the methods after this comment are considered thread-safe.
+	//Caution must be had to avoid calling more than one of the methods above simulatenously
+	void writeChannel(const AudioSampleBuffer& buffer, int channel, int sourceChannel, int nSamples, int64 timestamp);
+	bool startRead(Array<CircularBufferIndexes>& indexes, Array<int64>& timestamps, int nMax);
+	const AudioSampleBuffer& getAudioBufferReference() const;
+	void stopRead();
+	
+
+private:
+	void fillTimestamps(int channel, int index, int size, int64 timestamp);
+
+	OwnedArray<AbstractFifo> m_fifos;
+	AudioSampleBuffer m_buffer;
+	Array<int> m_readSamples;
+	OwnedArray<Array<int64>> m_timestamps;
+	Array<int64> m_lastReadTimestamps;
+
+	int m_numChans;
+	const int m_blockSize;
+	bool m_readInProgress;
+	int m_numBlocks;
+	int m_maxSize;
+
+	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DataQueue);
+};
+
+
+#endif  // DATAQUEUE_H_INCLUDED
diff --git a/Source/Processors/RecordNode/EngineConfigWindow.cpp b/Source/Processors/RecordNode/EngineConfigWindow.cpp
index e86beb6240f5ef28ce1344ce704c75701c494b04..c0f9601ac14ec9b4770f1ae70499e50c4ee55b73 100644
--- a/Source/Processors/RecordNode/EngineConfigWindow.cpp
+++ b/Source/Processors/RecordNode/EngineConfigWindow.cpp
@@ -1,25 +1,25 @@
 /*
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This file is part of the Open Ephys GUI
- Copyright (C) 2014 Florian Franzen
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
 
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- */
+*/
 
 #include "EngineConfigWindow.h"
 
diff --git a/Source/Processors/RecordNode/EngineConfigWindow.h b/Source/Processors/RecordNode/EngineConfigWindow.h
index e0f0bf823cac72e9e0fe99accd5bec3fdfc44c8c..61d22f0b572b6b913e7f81adb2454fddc6f3e05a 100644
--- a/Source/Processors/RecordNode/EngineConfigWindow.h
+++ b/Source/Processors/RecordNode/EngineConfigWindow.h
@@ -1,25 +1,25 @@
 /*
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This file is part of the Open Ephys GUI
- Copyright (C) 2014 Florian Franzen
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
 
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- */
+*/
 
 #ifndef ENGINECONFIGWINDOW_H_INCLUDED
 #define ENGINECONFIGWINDOW_H_INCLUDED
diff --git a/Source/Processors/RecordNode/EventQueue.h b/Source/Processors/RecordNode/EventQueue.h
new file mode 100644
index 0000000000000000000000000000000000000000..22dd238fc57847f7292f26d373ec7e4567cffef6
--- /dev/null
+++ b/Source/Processors/RecordNode/EventQueue.h
@@ -0,0 +1,141 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef EVENTQUEUE_H_INCLUDED
+#define EVENTQUEUE_H_INCLUDED
+
+#include "../../../JuceLibraryCode/JuceHeader.h"
+#include <vector>
+
+struct SpikeObject;
+
+template <class MsgContainer>
+class AsyncEventMessage :
+	public ReferenceCountedObject
+{
+public:
+	AsyncEventMessage(const MsgContainer& m, int64 t, int extra) : 
+		ReferenceCountedObject(),
+		m_data(m),
+		m_timestamp(t),
+		m_extra(extra)
+	{}
+
+	~AsyncEventMessage() {};
+
+	const MsgContainer& getData() const { return m_data;  }
+	const int64& getTimestamp() const { return m_timestamp; }
+	const int& getExtra() const { return m_extra;  }
+
+private:
+	const MsgContainer m_data;
+	const int64 m_timestamp;
+	const int m_extra;
+
+};
+
+template <class EventClass>
+class EventQueue
+{
+public:
+	typedef AsyncEventMessage<EventClass> EventContainer;
+	typedef ReferenceCountedObjectPtr<EventContainer> EventClassPtr;
+
+	EventQueue(int size) :
+		m_fifo(size)
+	{
+		m_data.resize(size);
+	}
+
+	~EventQueue()
+	{}
+
+	int getRemainingEvents() const
+	{
+		return m_fifo.getNumReady();
+	}
+
+	void reset()
+	{
+		m_data.clear();
+		m_data.resize(m_fifo.getTotalSize());
+	}
+
+	void resize(int size)
+	{
+		m_data.clear();
+		m_fifo.setTotalSize(size);
+		m_data.resize(size);
+	}
+
+	void addEvent(const EventClass& ev, int64 t, int extra = 0)
+	{
+		int pos1, size1, pos2, size2;
+		size1 = 0;
+		m_fifo.prepareToWrite(1, pos1, size1, pos2, size2);
+
+		/* This means there is a buffer overrun. Instead of overwritting the existing data and risking a collision of both threads
+			we just skip the incoming samples. TODO: use this to notify of the overrun and act consequently   */
+		if (size1 > 0)
+		{
+			m_data[pos1] = new EventContainer(ev, t, extra);
+			m_fifo.finishedWrite(1);
+		}
+	}
+
+	int getEvents(std::vector<EventClassPtr>& vec, int max)
+	{
+		int pos1, size1, pos2, size2;
+		int numAvailable = m_fifo.getNumReady();
+		int numToRead = ((max < numAvailable) && (max > 0)) ? max : numAvailable;
+		m_fifo.prepareToRead(numToRead, pos1, size1, pos2, size2);
+		vec.resize(numToRead);
+		for (int i = 0; i < size1; ++i)
+		{
+			vec[i] = m_data[pos1 + i];
+		}
+		if (size2 > 0)
+		{
+			for (int i = 0; i < size2; ++i)
+			{
+				vec[size1 + i] = m_data[pos2 + i];
+			}
+		}
+		m_fifo.finishedRead(numToRead);
+		return numToRead;
+	}
+
+private:
+	std::vector<EventClassPtr> m_data;
+	AbstractFifo m_fifo;
+
+	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EventQueue);
+};
+
+typedef EventQueue<MidiMessage> EventMsgQueue;
+typedef EventQueue<SpikeObject> SpikeMsgQueue;
+typedef ReferenceCountedObjectPtr<AsyncEventMessage<MidiMessage>> EventMessagePtr;
+typedef ReferenceCountedObjectPtr<AsyncEventMessage<SpikeObject>> SpikeMessagePtr;
+
+#endif  // EVENTQUEUE_H_INCLUDED
+
diff --git a/Source/Processors/RecordNode/OriginalRecording.cpp b/Source/Processors/RecordNode/OriginalRecording.cpp
index 864514ae6ed08e8bb97579bbe4d4a0a5f378ee4d..5205d144e8cf5b6a8f374f4e007352fd6149b036 100644
--- a/Source/Processors/RecordNode/OriginalRecording.cpp
+++ b/Source/Processors/RecordNode/OriginalRecording.cpp
@@ -1,23 +1,23 @@
 /*
-------------------------------------------------------------------
+    ------------------------------------------------------------------
 
-This file is part of the Open Ephys GUI
-Copyright (C) 2013 Florian Franzen
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
 
-------------------------------------------------------------------
+    ------------------------------------------------------------------
 
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 
@@ -67,7 +67,7 @@ String OriginalRecording::getEngineID()
     return "OPENEPHYS";
 }
 
-void OriginalRecording::addChannel(int index, Channel* chan)
+void OriginalRecording::addChannel(int index, const Channel* chan)
 {
     //Just populate the file array with null so we can address it by index afterwards
     fileArray.add(nullptr);
@@ -75,7 +75,7 @@ void OriginalRecording::addChannel(int index, Channel* chan)
     samplesSinceLastTimestamp.add(0);
 }
 
-void OriginalRecording::addSpikeElectrode(int index, SpikeRecordInfo* elec)
+void OriginalRecording::addSpikeElectrode(int index, const SpikeRecordInfo* elec)
 {
     spikeFileArray.add(nullptr);
 }
@@ -382,27 +382,23 @@ String OriginalRecording::generateSpikeHeader(SpikeRecordInfo* elec)
     return header;
 }
 
-void OriginalRecording::writeEvent(int eventType, MidiMessage& event, int samplePosition)
+void OriginalRecording::writeEvent(int eventType, const MidiMessage& event, int64 timestamp)
 {
     if (isWritableEvent(eventType))
-        writeTTLEvent(event,samplePosition);
+		writeTTLEvent(event, timestamp);
     if (eventType == GenericProcessor::MESSAGE)
-        writeMessage(event,samplePosition);
+		writeMessage(event, timestamp);
 }
 
-void OriginalRecording::writeMessage(MidiMessage& event, int samplePosition)
+void OriginalRecording::writeMessage(const MidiMessage& event, int64 timestamp)
 {
     if (messageFile == nullptr)
         return;
-    uint64 samplePos = (uint64) samplePosition;
-    uint8 sourceNodeId = event.getNoteNumber();
-
-    int64 eventTimestamp = (*timestamps)[sourceNodeId] + samplePos;
 
     int msgLength = event.getRawDataSize() - 6;
     const char* dataptr = (const char*)event.getRawData() + 6;
 
-    String timestampText(eventTimestamp);
+    String timestampText(timestamp);
 
     diskWriteLock.enter();
     fwrite(timestampText.toUTF8(),1,timestampText.length(),messageFile);
@@ -413,7 +409,7 @@ void OriginalRecording::writeMessage(MidiMessage& event, int samplePosition)
 
 }
 
-void OriginalRecording::writeTTLEvent(MidiMessage& event, int samplePosition)
+void OriginalRecording::writeTTLEvent(const MidiMessage& event, int64 timestamp)
 {
     // find file and write samples to disk
     // std::cout << "Received event!" << std::endl;
@@ -423,15 +419,12 @@ void OriginalRecording::writeTTLEvent(MidiMessage& event, int samplePosition)
 
     const uint8* dataptr = event.getRawData();
 
-    uint64 samplePos = (uint64) samplePosition;
-
-    uint8 sourceNodeId = event.getNoteNumber();
-
-    int64 eventTimestamp = (*timestamps)[sourceNodeId] + samplePos; // add the sample position to the buffer timestamp
+    //With the new external recording thread, this field has no sense.
+	int16 samplePos = 0;
 
     diskWriteLock.enter();
 
-    fwrite(&eventTimestamp,					// ptr
+    fwrite(&timestamp,					// ptr
            8,   							// size of each element
            1, 		  						// count
            eventFile);   			// ptr to FILE object
@@ -453,64 +446,59 @@ void OriginalRecording::writeTTLEvent(MidiMessage& event, int samplePosition)
     diskWriteLock.exit();
 }
 
-void OriginalRecording::writeData(AudioSampleBuffer& buffer)
+void OriginalRecording::writeData(int writeChannel, int realChannel, const float* buffer, int size)
 {
+	int samplesWritten = 0;
 
-    for (int i = 0; i < buffer.getNumChannels(); i++)
-    {
-        if (getChannel(i)->getRecordState())
-        {
-            int samplesWritten = 0;
-
-            int sourceNodeId = getChannel(i)->sourceNodeId;
+	int sourceNodeId = getChannel(realChannel)->sourceNodeId;
 
-            samplesSinceLastTimestamp.set(i,0);
+	//TODO: optimize. Now we use realchannel, we should optimize the whole thing to only use recorded channels
+	samplesSinceLastTimestamp.set(realChannel, 0);
 
-            int nSamples = (*numSamples)[sourceNodeId];
+	int nSamples = size;
 
             while (samplesWritten < nSamples) // there are still unwritten samples in this buffer
             {
                 int numSamplesToWrite = nSamples - samplesWritten;
 
-                if (blockIndex[i] + numSamplesToWrite < BLOCK_LENGTH) // we still have space in this block
+                if (blockIndex[realChannel] + numSamplesToWrite < BLOCK_LENGTH) // we still have space in this block
                 {
 
                     // write buffer to disk!
-                    writeContinuousBuffer(buffer.getReadPointer(i,samplesWritten),
+                    writeContinuousBuffer(buffer + samplesWritten,
                                           numSamplesToWrite,
-                                          i);
+                                          writeChannel);
 
                     //timestamp += numSamplesToWrite;
-                    samplesSinceLastTimestamp.set(i, samplesSinceLastTimestamp[i] + numSamplesToWrite);
-                    blockIndex.set(i, blockIndex[i] + numSamplesToWrite);
+                    samplesSinceLastTimestamp.set(realChannel, samplesSinceLastTimestamp[realChannel] + numSamplesToWrite);
+                    blockIndex.set(realChannel, blockIndex[realChannel] + numSamplesToWrite);
                     samplesWritten += numSamplesToWrite;
 
                 }
                 else   // there's not enough space left in this block for all remaining samples
                 {
 
-                    numSamplesToWrite = BLOCK_LENGTH - blockIndex[i];
+                    numSamplesToWrite = BLOCK_LENGTH - blockIndex[realChannel];
 
                     // write buffer to disk!
-                    writeContinuousBuffer(buffer.getReadPointer(i,samplesWritten),
+                    writeContinuousBuffer(buffer + samplesWritten,
                                           numSamplesToWrite,
-                                          i);
+                                          writeChannel);
 
                     // update our variables
                     samplesWritten += numSamplesToWrite;
                     //timestamp += numSamplesToWrite;
-                    samplesSinceLastTimestamp.set(i, samplesSinceLastTimestamp[i] + numSamplesToWrite);
-                    blockIndex.set(i,0); // back to the beginning of the block
+                    samplesSinceLastTimestamp.set(realChannel, samplesSinceLastTimestamp[realChannel] + numSamplesToWrite);
+                    blockIndex.set(realChannel,0); // back to the beginning of the block
                 }
             }
 
-        }
-    }
 
 }
 
-void OriginalRecording::writeContinuousBuffer(const float* data, int nSamples, int channel)
+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)
         return;
@@ -526,7 +514,7 @@ void OriginalRecording::writeContinuousBuffer(const float* data, int nSamples, i
 
     if (blockIndex[channel] == 0)
     {
-        writeTimestampAndSampleCount(fileArray[channel], channel);
+        writeTimestampAndSampleCount(fileArray[channel], writeChannel);
     }
 
     diskWriteLock.enter();
@@ -554,9 +542,9 @@ void OriginalRecording::writeTimestampAndSampleCount(FILE* file, int channel)
 
     uint16 samps = BLOCK_LENGTH;
 
-    int sourceNodeId = getChannel(channel)->sourceNodeId;
+   // int sourceNodeId = getChannel(channel)->sourceNodeId;
 
-    int64 ts = (*timestamps)[sourceNodeId] + samplesSinceLastTimestamp[channel];
+    int64 ts = getTimestamp(channel) + samplesSinceLastTimestamp[channel];
 
     fwrite(&ts,                       // ptr
            8,                               // size of each element
@@ -642,7 +630,7 @@ void OriginalRecording::closeFiles()
 //     this->timestamp = timestamp;
 // }
 
-void OriginalRecording::writeSpike(const SpikeObject& spike, int electrodeIndex)
+void OriginalRecording::writeSpike(int electrodeIndex, const SpikeObject& spike, int64 timestamp)
 {
     uint8_t spikeBuffer[MAX_SPIKE_BUFFER_LEN];
 
diff --git a/Source/Processors/RecordNode/OriginalRecording.h b/Source/Processors/RecordNode/OriginalRecording.h
index 82cd89092cbce28a99f3335e6deb65561f25fc1b..8a7e7dd3f887630eae1c3bdac922dbe465ac6bf7 100644
--- a/Source/Processors/RecordNode/OriginalRecording.h
+++ b/Source/Processors/RecordNode/OriginalRecording.h
@@ -1,26 +1,25 @@
 /*
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This file is part of the Open Ephys GUI
- Copyright (C) 2013 Florian Franzen
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
 
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
- */
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+*/
 #ifndef ORIGINALRECORDING_H_INCLUDED
 #define ORIGINALRECORDING_H_INCLUDED
 
@@ -47,15 +46,14 @@ public:
 
     void setParameter(EngineParameter& parameter);
     String getEngineID();
-    void openFiles(File rootFolder, int experimentNumber, int recordingNumber);
-    void closeFiles();
-    void writeData(AudioSampleBuffer& buffer);
-    void writeEvent(int eventType, MidiMessage& event, int samplePosition);
-    void addChannel(int index, Channel* chan);
-    void resetChannels();
-    //void updateTimeStamp(int64 timestamp);
-    void addSpikeElectrode(int index, SpikeRecordInfo* elec);
-    void writeSpike(const SpikeObject& spike, int electrodeIndex);
+    void openFiles(File rootFolder, int experimentNumber, int recordingNumber) override;
+	void closeFiles() override;
+	void writeData(int writeChannel, int realChannel, const float* buffer, int size) override;
+	void writeEvent(int eventType, const MidiMessage& event, int64 timestamp) override;
+	void addChannel(int index, const Channel* chan) override;
+	void resetChannels() override;
+	void addSpikeElectrode(int index, const SpikeRecordInfo* elec) override;
+	void writeSpike(int electrodeIndex, const SpikeObject& spike, int64 timestamp) override;
 
     static RecordEngineManager* getEngineManager();
 
@@ -71,8 +69,8 @@ private:
     String generateSpikeHeader(SpikeRecordInfo* elec);
 
     void openMessageFile(File rootFolder);
-    void writeTTLEvent(MidiMessage& event, int samplePosition);
-    void writeMessage(MidiMessage& event, int samplePosition);
+    void writeTTLEvent(const MidiMessage& event, int64 timestamp);
+    void writeMessage(const MidiMessage& event, int64 timestamp);
 
     void writeXml();
 
diff --git a/Source/Processors/RecordNode/RecordEngine.cpp b/Source/Processors/RecordNode/RecordEngine.cpp
index e62c06b4811c1dd8dc255f5a91305e78efcf32e4..4fb307ad0ab3229a58607631d7290dad836fc726 100644
--- a/Source/Processors/RecordNode/RecordEngine.cpp
+++ b/Source/Processors/RecordNode/RecordEngine.cpp
@@ -1,25 +1,25 @@
 /*
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This file is part of the Open Ephys GUI
- Copyright (C) 2014 Florian Franzen
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
 
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- */
+*/
 
 #include "RecordEngine.h"
 #include "RecordNode.h"
@@ -40,33 +40,52 @@ void RecordEngine::setParameter(EngineParameter& parameter) {}
 
 void RecordEngine::resetChannels() {}
 
-void RecordEngine::registerProcessor(GenericProcessor* processor) {}
+void RecordEngine::registerProcessor(const GenericProcessor* processor) {}
 
-Channel* RecordEngine::getChannel(int index)
+void RecordEngine::addChannel(int index, const Channel* chan) {}
+
+Channel* RecordEngine::getChannel(int index) const
 {
     return AccessClass::getProcessorGraph()->getRecordNode()->getDataChannel(index);
 }
 
-String RecordEngine::generateDateString()
+String RecordEngine::generateDateString() const
 {
     return AccessClass::getProcessorGraph()->getRecordNode()->generateDateString();
 }
 
-SpikeRecordInfo* RecordEngine::getSpikeElectrode(int index)
+SpikeRecordInfo* RecordEngine::getSpikeElectrode(int index) const
 {
     return AccessClass::getProcessorGraph()->getRecordNode()->getSpikeElectrode(index);
 }
 
-void RecordEngine::updateTimestamps(std::map<uint8, int64>* ts)
+void RecordEngine::updateTimestamps(const Array<int64>& ts, int channel)
 {
-    timestamps = ts;
+	if (channel < 0)
+		timestamps = ts;
+	else
+		timestamps.set(channel, ts[channel]);
 }
 
-void RecordEngine::updateNumSamples(std::map<uint8, int>* ns)
+void RecordEngine::setChannelMapping(const Array<int>& chans)
 {
-    numSamples = ns;
+	channelMap = chans;
 }
 
+int64 RecordEngine::getTimestamp(int channel) const
+{
+	return timestamps[channel];
+}
+
+int RecordEngine::getRealChannel(int channel) const
+{
+	return channelMap[channel];
+}
+
+int RecordEngine::getNumRecordedChannels() const
+{
+	return channelMap.size();
+}
 
 void RecordEngine::registerSpikeSource(GenericProcessor* processor) {}
 
diff --git a/Source/Processors/RecordNode/RecordEngine.h b/Source/Processors/RecordNode/RecordEngine.h
index e9fc8585fd9f1acdea83a530a987f362a23f9484..328967230378030ada630d83ca3a9bd3cd826778 100644
--- a/Source/Processors/RecordNode/RecordEngine.h
+++ b/Source/Processors/RecordNode/RecordEngine.h
@@ -1,25 +1,25 @@
 /*
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This file is part of the Open Ephys GUI
- Copyright (C) 2014 Florian Franzen
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
 
- ------------------------------------------------------------------
+    ------------------------------------------------------------------
 
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
 
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- GNU General Public License for more details.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
 
- You should have received a copy of the GNU General Public License
- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
- */
+*/
 
 #ifndef RECORDENGINE_H_INCLUDED
 #define RECORDENGINE_H_INCLUDED
@@ -61,21 +61,27 @@ public:
     virtual ~RecordEngine();
     virtual String getEngineID() =0;
 
-    /** All the public methods (except registerManager) are called by RecordNode:
+    /** All the public methods (except registerManager) are called by RecordNode or RecordingThread:
     When acquisition starts (in the specified order):
     	1-resetChannels
     	2-registerProcessor, addChannel, registerSpikeSource, addspikeelectrode
     	3-configureEngine (which calls setParameter)
     	3-startAcquisition
-    During acquisition:
-    	updateTimeStamps
     When recording starts (in the specified order):
     	1-directoryChanged (if needed)
-    	2-openFiles
-    During recording:
-    	writeData, writeEvent, writeSpike
+		2-(setChannelMapping)
+		3-(updateTimestamps*)
+    	4-openFiles*
+    During recording: (RecordThread loop)
+    	1-(updateTimestamps*)
+		2-writeData*
+		3-writeEvent* (if needed)
+		4-writeSpike* (if needed)
     When recording stops:
-    	closeFiles
+    	closeFiles*
+
+		Methods marked with a * are called via the RecordThread thread.
+		Methods marked with parenthesis are not overloaded methods
     */
 
     /** Called for registering parameters
@@ -91,25 +97,23 @@ public:
     */
     virtual void closeFiles() = 0;
 
-    /** Write continuous data.
-    	This method gets the full data buffer, it must query getRecordState for
-    	each registered channel to determine which channels to actually write to disk.
-        The number of samples to write will be found in the numSamples object.
+    /** Write continuous data for a channel. The raw buffer pointer is passed for speed, 
+		care must be taken to only read the specified number of bytes.
     */
-    virtual void writeData(AudioSampleBuffer& buffer) = 0;
+    virtual void writeData(int writeChannel, int realChannel, const float* buffer, int size) = 0;
 
     /** Write a single event to disk.
     */
-    virtual void writeEvent(int eventType, MidiMessage& event, int samplePosition) = 0;
+    virtual void writeEvent(int eventType, const MidiMessage& event, int64 timestamp) = 0;
 
     /** Called when acquisition starts once for each processor that might record continuous data
     */
-    virtual void registerProcessor(GenericProcessor* processor);
+    virtual void registerProcessor(const GenericProcessor* processor);
 
     /** Called after registerProcessor, once for each output
     	channel of the processor
     */
-    virtual void addChannel(int index, Channel* chan) = 0;
+    virtual void addChannel(int index, const Channel* chan);
 
     /** Called when acquisition starts once for each processor that might record spikes
     */
@@ -117,23 +121,25 @@ public:
 
     /** Called after registerSpikesource, once for each channel group
     */
-    virtual void addSpikeElectrode(int index, SpikeRecordInfo* elec) = 0;
+    virtual void addSpikeElectrode(int index, const SpikeRecordInfo* elec) = 0;
 
     /** Write a spike to disk
     */
-    virtual void writeSpike(const SpikeObject& spike, int electrodeIndex) = 0;
+    virtual void writeSpike(int electrodeIndex, const SpikeObject& spike, int64 timestamp) = 0;
 
     /** Called when a new acquisition starts, to clean all channel data
     	before registering the processors
     */
     virtual void resetChannels();
 
-    /** Called every time a new timestamp event is received
+    /** Called at the start of every write block
     */
-    void updateTimestamps(std::map<uint8, int64>* timestamps);
+    void updateTimestamps(const Array<int64>& timestamps, int channel = -1);
 
-    /** Called every time a new numSamples event is received */
-    void updateNumSamples(std::map<uint8, int>* numSamples);
+	/** Called prior to opening files, to set the map between recorded
+		channels and actual channel numbers
+	*/
+	void setChannelMapping(const Array<int>& channels);
 
     /** Called after all channels and spike groups have been registered,
     	just before acquisition starts
@@ -157,20 +163,31 @@ protected:
 
     /** Gets the specified channel from the channel array stored in RecordNode
     */
-    Channel* getChannel(int index);
+    Channel* getChannel(int index) const;
 
     /** Gets the specified channel group info structure from the array stored in RecordNode
     */
-    SpikeRecordInfo* getSpikeElectrode(int index);
+    SpikeRecordInfo* getSpikeElectrode(int index) const;
 
     /** Generate a Matlab-compatible datestring
     */
-    String generateDateString();
+    String generateDateString() const;
+
+	/** Gets the current block's first timestamp for a given channel
+	*/
+	int64 getTimestamp(int channel) const;
+
+	/** Gets the actual channel number from a recorded channel index
+	*/
+	int getRealChannel(int channel) const;
 
-    std::map<uint8, int>* numSamples;
-    std::map<uint8, int64>* timestamps;
+	/** Gets the number of recorded channels
+	*/
+	int getNumRecordedChannels() const;
 
 private:
+	Array<int64> timestamps;
+	Array<int> channelMap;
     RecordEngineManager* manager;
 
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RecordEngine);
diff --git a/Source/Processors/RecordNode/RecordNode.cpp b/Source/Processors/RecordNode/RecordNode.cpp
index 83a80bef5a0d233a74b718b56d0238b311439257..b41604eab08cfdc03cf1ab72789d4190ae33547d 100755
--- a/Source/Processors/RecordNode/RecordNode.cpp
+++ b/Source/Processors/RecordNode/RecordNode.cpp
@@ -27,6 +27,8 @@
 #include "../../UI/ControlPanel.h"
 #include "../../AccessClass.h"
 #include "RecordEngine.h"
+#include "RecordThread.h"
+#include "DataQueue.h"
 
 #define EVERY_ENGINE for(int eng = 0; eng < engineArray.size(); eng++) engineArray[eng]
 
@@ -41,15 +43,11 @@ RecordNode::RecordNode()
 
     isProcessing = false;
     isRecording = false;
-    allFilesOpened = false;
-    signalFilesShouldClose = false;
-
-    signalFilesShouldClose = false;
+	setFirstBlock = false;
 
     settings.numInputs = 2048;
     settings.numOutputs = 0;
 
-    eventChannel = new Channel(this, 0, EVENT_CHANNEL);
     recordingNumber = -1;
 
     spikeElectrodeIndex = 0;
@@ -60,13 +58,16 @@ RecordNode::RecordNode()
 
     // 128 inputs, 0 outputs
     setPlayConfigDetails(getNumInputs(),getNumOutputs(),44100.0,128);
-
+	m_recordThread = new RecordThread(engineArray);
+	m_dataQueue = new DataQueue(WRITE_BLOCK_LENGTH, DATA_BUFFER_NBLOCKS);
+	m_eventQueue = new EventMsgQueue(EVENT_BUFFER_NEVENTS);
+	m_spikeQueue = new SpikeMsgQueue(SPIKE_BUFFER_NSPIKES);
+	m_recordThread->setQueuePointers(m_dataQueue, m_eventQueue, m_spikeQueue);
 }
 
 
 RecordNode::~RecordNode()
 {
-    delete eventChannel; // Memory leak fixed by Michael Borisov
 }
 
 void RecordNode::setChannel(Channel* ch)
@@ -117,19 +118,6 @@ void RecordNode::filenameComponentChanged(FilenameComponent* fnc)
 
 }
 
-void RecordNode::updateChannelName(int channelIndex, String newname)
-{
-    /*  if (channelPointers[channelIndex] != nullptr && channelIndex < channelPointers.size())
-        {
-            channelPointers[channelIndex]->name = newname;
-            updateFileName(channelPointers[channelIndex]);
-        } else*/
-    {
-        // keep name and do the change when the pointer actually points to something... ?
-        modifiedChannelNames.add(newname);
-        modifiedChannelInd.add(channelIndex);
-    }
-}
 
 void RecordNode::getChannelNamesAndRecordingStatus(StringArray& names, Array<bool>& recording)
 {
@@ -186,17 +174,6 @@ void RecordNode::addInputChannel(GenericProcessor* sourceNode, int chan)
 
 }
 
-void RecordNode::updateTrialNumber()
-{
-    trialNum++;
-}
-
-void RecordNode::appendTrialNumber(bool t)
-{
-    appendTrialNum = t;
-}
-
-
 void RecordNode::createNewDirectory()
 {
     std::cout << "Creating new directory." << std::endl;
@@ -299,9 +276,8 @@ void RecordNode::setParameter(int parameterIndex, float newValue)
     if (parameterIndex == 1)
     {
 
-        isRecording = true;
-        hasRecorded = true;
-        // std::cout << "START RECORDING." << std::endl;
+		
+		// std::cout << "START RECORDING." << std::endl;
 
         if (newDirectoryNeeded)
         {
@@ -327,9 +303,31 @@ void RecordNode::setParameter(int parameterIndex, float newValue)
             settingsNeeded = false;
         }
 
-        EVERY_ENGINE->openFiles(rootFolder, experimentNumber, recordingNumber);
+		m_recordThread->setFileComponents(rootFolder, experimentNumber, recordingNumber);
+
+		channelMap.clear();
+		int totChans = channelPointers.size();
+		for (int ch = 0; ch < totChans; ++ch)
+		{
+			if (channelPointers[ch]->getRecordState())
+			{
+				channelMap.add(ch);
+			}
+		}
+		int numRecordedChannels = channelMap.size();
+
+		EVERY_ENGINE->setChannelMapping(channelMap);
+		m_recordThread->setChannelMap(channelMap);
+		m_dataQueue->setChannels(numRecordedChannels);
+		m_eventQueue->reset();
+		m_spikeQueue->reset();
+		m_recordThread->setFirstBlockFlag(false);
+
+		setFirstBlock = false;
+		m_recordThread->startThread();
 
-        allFilesOpened = true;
+		isRecording = true;
+		hasRecorded = true;
 
     }
     else if (parameterIndex == 0)
@@ -340,15 +338,29 @@ void RecordNode::setParameter(int parameterIndex, float newValue)
 
         if (isRecording)
         {
-
-            // close necessary files
-            signalFilesShouldClose = true;
+			isRecording = false;
+
+            // close the writing thread.
+			m_recordThread->signalThreadShouldExit();
+			m_recordThread->waitForThreadToExit(2000);
+			while (m_recordThread->isThreadRunning())
+			{
+				
+				if (AlertWindow::showOkCancelBox(AlertWindow::WarningIcon, "Record Thread timeout",
+					"The recording thread is taking too long to close.\nThis could mean there is still data waiting to be written in the buffer, but it normally "
+					"shouldn't take this long.\nYou can either wait a bit more or forcefully close the thread. Note that data might be lost or corrupted"
+					"if forcibly closing the thread.", "Stop the thread", "Wait a bit more"))
+				{
+					m_recordThread->stopThread(100);
+					m_recordThread->forceCloseFiles();
+				}
+				else
+				{
+					m_recordThread->waitForThreadToExit(2000);
+				}
+			}
 
         }
-
-        isRecording = false;
-
-
     }
     else if (parameterIndex == 2)
     {
@@ -379,15 +391,6 @@ void RecordNode::setParameter(int parameterIndex, float newValue)
     }
 }
 
-void RecordNode::closeAllFiles()
-{
-    if (allFilesOpened)
-    {
-        EVERY_ENGINE->closeFiles();
-        allFilesOpened = false;
-    }
-}
-
 bool RecordNode::enable()
 {
     if (hasRecorded)
@@ -411,9 +414,6 @@ bool RecordNode::disable()
     // close files if necessary
     setParameter(0, 10.0f);
 
-    if (isProcessing)
-        closeAllFiles();
-
     isProcessing = false;
 
     return true;
@@ -427,13 +427,15 @@ float RecordNode::getFreeSpace()
 
 void RecordNode::handleEvent(int eventType, MidiMessage& event, int samplePosition)
 {
-    if (isRecording && allFilesOpened)
+    if (isRecording)
     {
         if (isWritableEvent(eventType))
         {
             if (*(event.getRawData()+4) > 0) // saving flag > 0 (i.e., event has not already been processed)
             {
-                EVERY_ENGINE->writeEvent(eventType, event, samplePosition);
+				uint8 sourceNodeId = event.getNoteNumber();
+				int64 timestamp = timestamps[sourceNodeId] + samplePosition;
+				m_eventQueue->addEvent(event, timestamp, eventType);
             }
         }
     }
@@ -442,34 +444,32 @@ void RecordNode::handleEvent(int eventType, MidiMessage& event, int samplePositi
 void RecordNode::process(AudioSampleBuffer& buffer,
                          MidiBuffer& events)
 {
-	//update timstamp data even if we're not recording yet
-	EVERY_ENGINE->updateTimestamps(&timestamps);
-	EVERY_ENGINE->updateNumSamples(&numSamples);
 	
 	// FIRST: cycle through events -- extract the TTLs and the timestamps
     checkForEvents(events);
 
-    if (isRecording && allFilesOpened)
+    if (isRecording)
     {
         // SECOND: write channel data
-        if (channelPointers.size() > 0)
-        {
-            EVERY_ENGINE->writeData(buffer);
-        }
+		int recordChans = channelMap.size();
+		for (int chan = 0; chan < recordChans; ++chan)
+		{
+			int realChan = channelMap[chan];
+			int sourceNodeId = channelPointers[realChan]->sourceNodeId;
+			int nSamples = numSamples.at(sourceNodeId);
+			int timestamp = timestamps.at(sourceNodeId);
+			m_dataQueue->writeChannel(buffer, chan, realChan, nSamples, timestamp);
+		}
 
         //  std::cout << nSamples << " " << samplesWritten << " " << blockIndex << std::endl;
-
-        return;
-
+		if (!setFirstBlock)
+		{
+			m_recordThread->setFirstBlockFlag(true);
+			setFirstBlock = true;
+		}
+        
     }
 
-    // this is intended to prevent parameter changes from closing files
-    // before recording stops
-    if (signalFilesShouldClose)
-    {
-        closeAllFiles();
-        signalFilesShouldClose = false;
-    }
 
 }
 
@@ -488,7 +488,7 @@ void RecordNode::registerRecordEngine(RecordEngine* engine)
     engineArray.add(engine);
 }
 
-void RecordNode::registerSpikeSource(GenericProcessor* processor)
+void RecordNode::registerSpikeSource(GenericProcessor* processor) 
 {
     EVERY_ENGINE->registerSpikeSource(processor);
 }
@@ -503,7 +503,10 @@ int RecordNode::addSpikeElectrode(SpikeRecordInfo* elec)
 
 void RecordNode::writeSpike(SpikeObject& spike, int electrodeIndex)
 {
-    EVERY_ENGINE->writeSpike(spike,electrodeIndex);
+	if (isRecording)
+	{
+		m_spikeQueue->addEvent(spike, spike.timestamp, electrodeIndex);
+	}
 }
 
 SpikeRecordInfo* RecordNode::getSpikeElectrode(int index)
diff --git a/Source/Processors/RecordNode/RecordNode.h b/Source/Processors/RecordNode/RecordNode.h
index 70facf9f34c5780e95188806916f3842f31ae964..92af93e5920e4f1e46f0e4e45ad417c5211a875e 100755
--- a/Source/Processors/RecordNode/RecordNode.h
+++ b/Source/Processors/RecordNode/RecordNode.h
@@ -26,18 +26,23 @@
 #include "../../../JuceLibraryCode/JuceHeader.h"
 #include <stdio.h>
 #include <map>
+#include <atomic>
 
 
 #include "../GenericProcessor/GenericProcessor.h"
 #include "../Channel/Channel.h"
+#include "EventQueue.h"
 
-
-#define HEADER_SIZE 1024
-#define BLOCK_LENGTH 1024
+#define WRITE_BLOCK_LENGTH 1024
+#define DATA_BUFFER_NBLOCKS 300
+#define EVENT_BUFFER_NEVENTS 512
+#define SPIKE_BUFFER_NSPIKES 512
 
 struct SpikeRecordInfo;
 struct SpikeObject;
 class RecordEngine;
+class RecordThread;
+class DataQueue;
 
 /**
 
@@ -92,9 +97,6 @@ public:
     /** returns channel names and whether we record them */
     void getChannelNamesAndRecordingStatus(StringArray& names, Array<bool>& recording);
 
-    /** update channel name */
-    void updateChannelName(int channelIndex, String newname);
-
     /** Get channel stored in channelPointers array
     */
     Channel* getDataChannel(int index);
@@ -132,10 +134,6 @@ public:
         return rootFolder;
     }
 
-    void appendTrialNumber(bool);
-
-    void updateTrialNumber();
-
     /** Adds a Record Engine to use
     */
     void registerRecordEngine(RecordEngine* engine);
@@ -163,8 +161,7 @@ public:
     /** Signals when to create a new data directory when recording starts.*/
     bool newDirectoryNeeded;
 
-    bool isRecording;
-    bool allFilesOpened;
+    std::atomic<bool> isRecording;
 
     /** Generate a Matlab-compatible datestring */
     String generateDateString();
@@ -173,7 +170,7 @@ private:
 
     /** Keep the RecordNode informed of acquisition and record states.
     */
-    bool isProcessing, signalFilesShouldClose;
+    bool isProcessing;
 
     /** User-selectable directory for saving data files. Currently
         defaults to the user's home directory.
@@ -196,16 +193,14 @@ private:
     */
     Time timer;
 
-    /** Closes all open files after recording has finished.
-    */
-    void closeAllFiles();
-
     /** Pointers to all continuous channels */
     Array<Channel*> channelPointers;
 
     /** Pointers to all event channels */
     Array<Channel*> eventChannelPointers;
 
+	Array<int> channelMap;
+
     OwnedArray<SpikeRecordInfo> spikeElectrodePointers;
 
     int spikeElectrodeIndex;
@@ -213,41 +208,22 @@ private:
     int experimentNumber;
     bool hasRecorded;
     bool settingsNeeded;
-
+	std::atomic<bool> setFirstBlock;
     /** Generates a default directory name, based on the current date and time */
     String generateDirectoryName();
 
     /** Cycle through the event buffer, looking for data to save */
     void handleEvent(int eventType, MidiMessage& event, int samplePos);
 
-    /** Object for holding information about the events file */
-    Channel* eventChannel;
-
-    /** Method for writing continuous buffers to disk.
-    */
-    void writeContinuousBuffer(const float* data, int nSamples, int channel);
-
-    /** Method for writing event buffers to disk.
-    */
-    void writeEventBuffer(MidiMessage& event, int samplePos);
-
-    void writeRecordMarker(FILE*);
-    void writeTimestampAndSampleCount(FILE*);
-
-    /** Used to indicate the end of each record */
-    char* recordMarker;
-
-    CriticalSection diskWriteLock;
-
-    Array<String> modifiedChannelNames;
-    Array<int> modifiedChannelInd;
-
-    bool appendTrialNum;
-    int trialNum;
-
     /**RecordEngines loaded**/
     OwnedArray<RecordEngine> engineArray;
 
+	ScopedPointer<RecordThread> m_recordThread;
+	ScopedPointer<DataQueue> m_dataQueue;
+	ScopedPointer<EventMsgQueue> m_eventQueue;
+	ScopedPointer<SpikeMsgQueue> m_spikeQueue;
+	
+	Array<int> m_recordedChannelMap;
 
     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RecordNode);
 
diff --git a/Source/Processors/RecordNode/RecordThread.cpp b/Source/Processors/RecordNode/RecordThread.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fcf7cff7400c5ebadfc8f7bd9507b80725aea7e7
--- /dev/null
+++ b/Source/Processors/RecordNode/RecordThread.cpp
@@ -0,0 +1,154 @@
+/*
+	------------------------------------------------------------------
+
+	This file is part of the Open Ephys GUI
+	Copyright (C) 2014 Open Ephys
+
+	------------------------------------------------------------------
+
+	This program is free software: you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation, either version 3 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+	*/
+
+#include "RecordThread.h"
+#include "../Visualization/SpikeObject.h"
+#include "RecordEngine.h"
+
+#define EVERY_ENGINE for(int eng = 0; eng < m_engineArray.size(); eng++) m_engineArray[eng]
+
+
+RecordThread::RecordThread(const OwnedArray<RecordEngine>& engines) :
+Thread("Record Thread"),
+m_engineArray(engines),
+m_receivedFirstBlock(false),
+m_cleanExit(true)
+{
+}
+
+RecordThread::~RecordThread()
+{
+}
+
+void RecordThread::setFileComponents(File rootFolder, int experimentNumber, int recordingNumber)
+{
+	if (isThreadRunning())
+		return;
+
+	m_rootFolder = rootFolder;
+	m_experimentNumber = experimentNumber;
+	m_recordingNumber = recordingNumber;
+}
+
+void RecordThread::setChannelMap(const Array<int>& channels)
+{
+	if (isThreadRunning())
+		return;
+	m_channelArray = channels;
+	m_numChannels = channels.size();
+}
+
+void RecordThread::setQueuePointers(DataQueue* data, EventMsgQueue* events, SpikeMsgQueue* spikes)
+{
+	m_dataQueue = data;
+	m_eventQueue = events;
+	m_spikeQueue = spikes;
+}
+
+void RecordThread::setFirstBlockFlag(bool state)
+{
+	m_receivedFirstBlock = state;
+	this->notify();
+}
+
+void RecordThread::run()
+{
+	const AudioSampleBuffer& dataBuffer = m_dataQueue->getAudioBufferReference();
+	bool closeEarly = true;
+	//1-Wait until the first block has arrived, so we can align the timestamps
+	while (!m_receivedFirstBlock && !threadShouldExit())
+	{
+		wait(100);
+	}
+
+	//2-Open Files
+	if (!threadShouldExit())
+	{
+		m_cleanExit = false;
+		closeEarly = false;
+		Array<int64> timestamps;
+		m_dataQueue->getTimestampsForBlock(0, timestamps);
+		EVERY_ENGINE->updateTimestamps(timestamps);
+		EVERY_ENGINE->openFiles(m_rootFolder, m_experimentNumber, m_recordingNumber);
+	}
+	//3-Normal loop
+	while (!threadShouldExit())
+	{
+		writeData(dataBuffer, BLOCK_MAX_WRITE_SAMPLES, BLOCK_MAX_WRITE_EVENTS, BLOCK_MAX_WRITE_SPIKES);
+	}
+	//4-Before closing the thread, try to write the remaining samples
+	if (!closeEarly)
+	{
+		writeData(dataBuffer, -1, -1, -1);
+
+		//5-Close files
+		EVERY_ENGINE->closeFiles();
+	}
+	m_cleanExit = true;
+	m_receivedFirstBlock = false;
+}
+
+void RecordThread::writeData(const AudioSampleBuffer& dataBuffer, int maxSamples, int maxEvents, int maxSpikes)
+{
+	Array<int64> timestamps;
+	Array<CircularBufferIndexes> idx;
+	m_dataQueue->startRead(idx, timestamps, maxSamples);
+	EVERY_ENGINE->updateTimestamps(timestamps);
+	for (int chan = 0; chan < m_numChannels; ++chan)
+	{
+		if (idx[chan].size1 > 0)
+		{
+			EVERY_ENGINE->writeData(chan, m_channelArray[chan], dataBuffer.getReadPointer(chan, idx[chan].index1), idx[chan].size1);
+			if (idx[chan].size2 > 0)
+			{
+				timestamps.set(chan, timestamps[chan] + idx[chan].size1);
+				EVERY_ENGINE->updateTimestamps(timestamps, chan);
+				EVERY_ENGINE->writeData(chan, m_channelArray[chan], dataBuffer.getReadPointer(chan, idx[chan].index2), idx[chan].size2);
+			}
+		}
+	}
+	m_dataQueue->stopRead();
+
+	std::vector<EventMessagePtr> events;
+	int nEvents = m_eventQueue->getEvents(events, maxEvents);
+	for (int ev = 0; ev < nEvents; ++ev)
+	{
+		EVERY_ENGINE->writeEvent(events[ev]->getExtra(), events[ev]->getData(), events[ev]->getTimestamp());
+	}
+
+	std::vector<SpikeMessagePtr> spikes;
+	int nSpikes = m_spikeQueue->getEvents(spikes, maxSpikes);
+	for (int sp = 0; sp < nSpikes; ++sp)
+	{
+		EVERY_ENGINE->writeSpike(spikes[sp]->getExtra(), spikes[sp]->getData(), spikes[sp]->getTimestamp());
+	}
+}
+
+void RecordThread::forceCloseFiles()
+{
+	if (isThreadRunning() || m_cleanExit)
+		return;
+
+	EVERY_ENGINE->closeFiles();
+	m_cleanExit = true;
+}
\ No newline at end of file
diff --git a/Source/Processors/RecordNode/RecordThread.h b/Source/Processors/RecordNode/RecordThread.h
new file mode 100644
index 0000000000000000000000000000000000000000..30c2c28057741260b632b8f4637d17edcc7c3ef2
--- /dev/null
+++ b/Source/Processors/RecordNode/RecordThread.h
@@ -0,0 +1,74 @@
+/*
+    ------------------------------------------------------------------
+
+    This file is part of the Open Ephys GUI
+    Copyright (C) 2014 Open Ephys
+
+    ------------------------------------------------------------------
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef RECORDTHREAD_H_INCLUDED
+#define RECORDTHREAD_H_INCLUDED
+
+#include "../../../JuceLibraryCode/JuceHeader.h"
+#include "EventQueue.h"
+#include "DataQueue.h"
+#include <atomic>
+
+#define BLOCK_MAX_WRITE_SAMPLES 4096
+#define BLOCK_MAX_WRITE_EVENTS 32
+#define BLOCK_MAX_WRITE_SPIKES 32
+
+class Channel;
+class RecordEngine;
+
+
+class RecordThread : public Thread
+{
+public:
+	RecordThread(const OwnedArray<RecordEngine>& engines);
+	~RecordThread();
+	void setFileComponents(File rootFolder, int experimentNumber, int recordingNumber);
+	void setChannelMap(const Array<int>& channels);
+	void setQueuePointers(DataQueue* data, EventMsgQueue* events, SpikeMsgQueue* spikes);
+
+	void run() override;
+
+	void setFirstBlockFlag(bool state);
+	void forceCloseFiles();
+
+private:
+	void writeData(const AudioSampleBuffer& buffer, int maxSamples, int maxEvents, int maxSpikes);
+
+	const OwnedArray<RecordEngine>& m_engineArray;
+	Array<int> m_channelArray;
+	
+	DataQueue* m_dataQueue;
+	EventMsgQueue* m_eventQueue;
+	SpikeMsgQueue *m_spikeQueue;
+
+	std::atomic<bool> m_receivedFirstBlock;
+	std::atomic<bool> m_cleanExit;
+
+	File m_rootFolder;
+	int m_experimentNumber;
+	int m_recordingNumber;
+	int m_numChannels;
+	JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(RecordThread);
+};
+
+#endif  // RECORDTHREAD_H_INCLUDED
diff --git a/Source/UI/ControlPanel.cpp b/Source/UI/ControlPanel.cpp
index 987121fc30c86e2740f82e1dfd6e2076ac082bf7..b5328948a98abd20e0f53e1328070471e36d7bce 100755
--- a/Source/UI/ControlPanel.cpp
+++ b/Source/UI/ControlPanel.cpp
@@ -552,6 +552,30 @@ void ControlPanel::updateRecordEngineList()
 		recordSelector->setSelectedId(selectedEngine, sendNotification);
 }
 
+String ControlPanel::getSelectedRecordEngineId()
+{
+	return recordEngines[recordSelector->getSelectedId() - 1]->getID();
+}
+
+bool ControlPanel::setSelectedRecordEngineId(String id)
+{
+	if (getAcquisitionState())
+	{
+		return false;
+	}
+
+	int nEngines = recordEngines.size();
+	for (int i = 0; i < nEngines; ++i)
+	{
+		if (recordEngines[i]->getID() == id)
+		{
+			recordSelector->setSelectedId(i + 1, sendNotificationSync);
+			return true;
+		}
+	}
+	return false;
+}
+
 void ControlPanel::createPaths()
 {
     /*  int w = getWidth() - 325;
diff --git a/Source/UI/ControlPanel.h b/Source/UI/ControlPanel.h
index cec8bc11898f033caea0ed8bc4087bc965136579..f63296ecf6761813a3bc7548691443b6b1384e2d 100755
--- a/Source/UI/ControlPanel.h
+++ b/Source/UI/ControlPanel.h
@@ -365,6 +365,10 @@ public:
 
     void updateRecordEngineList();
 
+	String getSelectedRecordEngineId();
+
+	bool setSelectedRecordEngineId(String id);
+
     ScopedPointer<RecordButton> recordButton;
 private:
     ScopedPointer<PlayButton> playButton;
diff --git a/open-ephys.jucer b/open-ephys.jucer
index 62023b4f198eee86f8f6732aafa8ef24a6f24770..6ff0cb146a8fd6465e81d48c30172d11db7c28d5 100644
--- a/open-ephys.jucer
+++ b/open-ephys.jucer
@@ -474,6 +474,12 @@
                 file="Source/Processors/ProcessorGraph/ProcessorGraph.h"/>
         </GROUP>
         <GROUP id="{72D807AC-44A0-1F7A-8699-22225876FE9A}" name="RecordNode">
+          <FILE id="WQxge0" name="DataQueue.cpp" compile="1" resource="0" file="Source/Processors/RecordNode/DataQueue.cpp"/>
+          <FILE id="cZPfsG" name="DataQueue.h" compile="0" resource="0" file="Source/Processors/RecordNode/DataQueue.h"/>
+          <FILE id="mcvfV8" name="EventQueue.h" compile="0" resource="0" file="Source/Processors/RecordNode/EventQueue.h"/>
+          <FILE id="r8K6Sh" name="RecordThread.cpp" compile="1" resource="0"
+                file="Source/Processors/RecordNode/RecordThread.cpp"/>
+          <FILE id="Q8yVpr" name="RecordThread.h" compile="0" resource="0" file="Source/Processors/RecordNode/RecordThread.h"/>
           <FILE id="deQ9TU" name="EngineConfigWindow.cpp" compile="1" resource="0"
                 file="Source/Processors/RecordNode/EngineConfigWindow.cpp"/>
           <FILE id="iSAT0P" name="EngineConfigWindow.h" compile="0" resource="0"