@@ -97,7 +97,7 @@ def _parse_header(self):
9797 event_stream_names = []
9898
9999 self ._num_of_signal_streams = len (sig_stream_names )
100-
100+
101101 # first loop to reassign stream by "stream_index" instead of "stream_name"
102102 self ._sig_streams = {}
103103 self ._evt_streams = {}
@@ -123,7 +123,7 @@ def _parse_header(self):
123123 # signals zone
124124 # create signals channel map: several channel per stream
125125 signal_channels = []
126-
126+
127127 for stream_index , stream_name in enumerate (sig_stream_names ):
128128 # stream_index is the index in vector stream names
129129 stream_id = str (stream_index )
@@ -141,15 +141,15 @@ def _parse_header(self):
141141 units = "uV"
142142 else :
143143 units = chan_info ["units" ]
144-
144+
145145 if "ADC" in chan_id :
146146 # These are non-neural channels and their stream should be separated
147147 # We defined their stream_id as the stream_index of neural data plus the number of neural streams
148148 # This is to not break backwards compatbility with the stream_id numbering
149149 stream_id = str (stream_index + len (sig_stream_names ))
150150 # For ADC channels multiplying by the bit_volts when units are not provided converts to Volts
151151 units = "V" if units == "" else units
152-
152+
153153 gain = chan_info ["bit_volts" ]
154154 offset = 0.0
155155 new_channels .append (
@@ -166,12 +166,12 @@ def _parse_header(self):
166166 )
167167 )
168168 signal_channels .extend (new_channels )
169-
169+
170170 signal_channels = np .array (signal_channels , dtype = _signal_channel_dtype )
171171
172172 signal_streams = []
173173 signal_buffers = []
174-
174+
175175 unique_streams_ids = np .unique (signal_channels ["stream_id" ])
176176 for stream_id in unique_streams_ids :
177177 # Handle special case of Synch channel having stream_id empty
@@ -184,17 +184,16 @@ def _parse_header(self):
184184 buffer_id = stream_id
185185 # We add the buffers here as both the neural and the ADC channels are in the same buffer
186186 signal_buffers .append ((stream_name , buffer_id ))
187- else : # This names the ADC streams
187+ else : # This names the ADC streams
188188 neural_stream_index = stream_index - self ._num_of_signal_streams
189189 neural_stream_name = sig_stream_names [neural_stream_index ]
190190 stream_name = f"{ neural_stream_name } _ADC"
191191 buffer_id = str (neural_stream_index )
192192 signal_streams .append ((stream_name , stream_id , buffer_id ))
193-
193+
194194 signal_streams = np .array (signal_streams , dtype = _signal_stream_dtype )
195195 signal_buffers = np .array (signal_buffers , dtype = _signal_buffer_dtype )
196196
197-
198197 # create memmap for signals
199198 self ._buffer_descriptions = {}
200199 self ._stream_buffer_slice = {}
@@ -223,30 +222,45 @@ def _parse_header(self):
223222 raise ValueError (
224223 "SYNC channel is not present in the recording. " "Set load_sync_channel to False"
225224 )
226-
227- num_neural_channels = sum (1 for ch in info ["channels" ] if "ADC" not in ch ["channel_name" ])
228- num_non_neural_channels = sum (1 for ch in info ["channels" ] if "ADC" in ch ["channel_name" ])
229-
230-
231- if num_non_neural_channels == 0 :
225+
226+ # Check if ADC and non-ADC channels are contiguous
227+ is_adc = ["ADC" in ch ["channel_name" ] for ch in info ["channels" ]]
228+ first_adc = is_adc .index (True ) if True in is_adc else len (is_adc )
229+ if any (not x for x in is_adc [first_adc :]):
230+ raise ValueError (
231+ "Interleaved ADC and non-ADC channels are not supported. "
232+ "ADC channels must be contiguous. Open an issue in python-neo to request this feature."
233+ )
234+
235+
236+ # Find sync channel and verify it's the last channel
237+ sync_index = next (
238+ (index for index , ch in enumerate (info ["channels" ]) if ch ["channel_name" ].endswith ("_SYNC" )), None
239+ )
240+ if sync_index is not None and sync_index != num_channels - 1 :
241+ raise ValueError (
242+ "SYNC channel must be the last channel in the buffer. Open an issue in python-neo to request this feature."
243+ )
244+
245+ num_neural_channels = sum (1 for ch_info in info ["channels" ] if "ADC" not in ch_info ["channel_name" ])
246+ num_non_neural_channels = sum (1 for ch_info in info ["channels" ] if "ADC" in ch_info ["channel_name" ])
247+
248+ if num_non_neural_channels == 0 :
232249 if has_sync_trace and not self .load_sync_channel :
233250 self ._stream_buffer_slice [stream_id ] = slice (None , - 1 )
234251 else :
235252 self ._stream_buffer_slice [stream_id ] = None
236253 else :
237- # For ADC channels, we remove the last channel which is the Synch channel
238254 stream_id_neural = stream_id
239255 stream_id_non_neural = str (int (stream_id ) + self ._num_of_signal_streams )
240-
241- # Note this implementation assumes that the neural channels come before the non-neural channels
242256
243257 self ._stream_buffer_slice [stream_id_neural ] = slice (0 , num_neural_channels )
244- self ._stream_buffer_slice [stream_id_non_neural ] = slice (num_neural_channels , None )
245-
246- # It also assumes that the synch channel is the last channel in the buffer
258+
247259 if has_sync_trace and not self .load_sync_channel :
248260 self ._stream_buffer_slice [stream_id_non_neural ] = slice (num_neural_channels , - 1 )
249-
261+ else :
262+ self ._stream_buffer_slice [stream_id_non_neural ] = slice (num_neural_channels , None )
263+
250264 # events zone
251265 # channel map: one channel one stream
252266 event_channels = []
@@ -484,8 +498,8 @@ def _get_signal_t_start(self, block_index, seg_index, stream_index):
484498 if stream_index < self ._num_of_signal_streams :
485499 _sig_stream_index = stream_index
486500 else :
487- _sig_stream_index = stream_index - self ._num_of_signal_streams
488-
501+ _sig_stream_index = stream_index - self ._num_of_signal_streams
502+
489503 t_start = self ._sig_streams [block_index ][seg_index ][_sig_stream_index ]["t_start" ]
490504 return t_start
491505
0 commit comments