Skip to content

Commit cb5b7a8

Browse files
committed
Refactor a bit function for exploring meta data.
This is needed for spikeinetrface internal mainly.
1 parent 5f8cdb7 commit cb5b7a8

File tree

1 file changed

+104
-95
lines changed

1 file changed

+104
-95
lines changed

neo/rawio/spikeglxrawio.py

Lines changed: 104 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -236,105 +236,17 @@ def scan_files(dirname):
236236
info_list = []
237237

238238
for root, dirs, files in os.walk(dirname):
239-
240239
for file in files:
241240
if not file.endswith('.meta'):
242241
continue
243242
meta_filename = Path(root) / file
244-
bin_filename = Path(root) / file.replace('.meta', '.bin')
243+
bin_filename = meta_filename.with_suffix('.bin')
245244
if meta_filename.exists() and bin_filename.exists():
246245
meta = read_meta_file(meta_filename)
247-
else:
248-
continue
249-
250-
num_chan = int(meta['nSavedChans'])
251-
252-
# Example file name structure:
253-
# Consider the filenames: `Noise4Sam_g0_t0.nidq.bin` or `Noise4Sam_g0_t0.imec0.lf.bin`
254-
# The filenames consist of 3 or 4 parts separated by `.`
255-
# 1. "Noise4Sam_g0_t0" will be the `name` variable. This choosen by the user
256-
# at recording time.
257-
# 2. "_gt0_" will give the `seg_index` (here 0)
258-
# 3. "nidq" or "imec0" will give the `device` variable
259-
# 4. "lf" or "ap" will be the `signal_kind` variable
260-
# `stream_name` variable is the concatenation of `device.signal_kind`
261-
name = file.split('.')[0]
262-
r = re.findall(r'_g(\d*)_t', name)
263-
seg_index = int(r[0][0])
264-
device = file.split('.')[1]
265-
if 'imec' in device:
266-
signal_kind = file.split('.')[2]
267-
stream_name = device + '.' + signal_kind
268-
units = 'uV'
269-
# please note the 1e6 in gain for this uV
270-
271-
# metad['imroTbl'] contain two gain per channel AP and LF
272-
# except for the last fake channel
273-
per_channel_gain = np.ones(num_chan, dtype='float64')
274-
if 'imDatPrb_type' not in meta or meta['imDatPrb_type'] == '0':
275-
# This work with NP 1.0 case with different metadata versions
276-
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_3A.md#imec
277-
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_3B1.md#imec
278-
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_3B2.md#imec
279-
if signal_kind == 'ap':
280-
index_imroTbl = 3
281-
elif signal_kind == 'lf':
282-
index_imroTbl = 4
283-
for c in range(num_chan - 1):
284-
v = meta['imroTbl'][c].split(' ')[index_imroTbl]
285-
per_channel_gain[c] = 1. / float(v)
286-
gain_factor = float(meta['imAiRangeMax']) / 512
287-
channel_gains = gain_factor * per_channel_gain * 1e6
288-
elif meta['imDatPrb_type'] in ('21', '24') and signal_kind == 'ap':
289-
# This work with NP 2.0 case with different metadata versions
290-
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_20.md#channel-entries-by-type
291-
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_20.md#imec
292-
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_30.md#imec
293-
per_channel_gain[:-1] = 1 / 80.
294-
gain_factor = float(meta['imAiRangeMax']) / 8192
295-
channel_gains = gain_factor * per_channel_gain * 1e6
296-
else:
297-
raise NotImplementedError('This meta file version of spikeglx'
298-
'is not implemented')
299-
else:
300-
signal_kind = ''
301-
stream_name = device
302-
units = 'V'
303-
channel_gains = np.ones(num_chan)
304-
305-
# there are differents kinds of channels with different gain values
306-
mn, ma, xa, dw = [int(e) for e in meta['snsMnMaXaDw'].split(sep=',')]
307-
per_channel_gain = np.ones(num_chan, dtype='float64')
308-
per_channel_gain[0:mn] = 1. / float(meta['niMNGain'])
309-
per_channel_gain[mn:mn + ma] = 1. / float(meta['niMAGain'])
310-
# this scaling come from the code in this zip
311-
# https://billkarsh.github.io/SpikeGLX/Support/SpikeGLX_Datafile_Tools.zip
312-
# in file readSGLX.py line76
313-
# this is equivalent of 2**15
314-
gain_factor = float(meta['niAiRangeMax']) / 32768
315-
channel_gains = per_channel_gain * gain_factor
316-
317-
info = {}
318-
info['name'] = name
319-
info['meta'] = meta
320-
info['meta_file'] = str(meta_filename)
321-
info['bin_file'] = str(bin_filename)
322-
for k in ('niSampRate', 'imSampRate'):
323-
if k in meta:
324-
info['sampling_rate'] = float(meta[k])
325-
info['num_chan'] = num_chan
326-
327-
info['sample_length'] = int(meta['fileSizeBytes']) // 2 // num_chan
328-
info['seg_index'] = seg_index
329-
info['device'] = device
330-
info['signal_kind'] = signal_kind
331-
info['stream_name'] = stream_name
332-
info['units'] = units
333-
info['channel_names'] = [txt.split(';')[0] for txt in meta['snsChanMap']]
334-
info['channel_gains'] = channel_gains
335-
info['channel_offsets'] = np.zeros(info['num_chan'])
336-
337-
info_list.append(info)
246+
info = extract_stream_info(meta_filename, meta)
247+
info['meta_file'] = str(meta_filename)
248+
info['bin_file'] = str(bin_filename)
249+
info_list.append(info)
338250

339251
return info_list
340252

@@ -344,7 +256,7 @@ def read_meta_file(meta_file):
344256
with open(meta_file, mode='r') as f:
345257
lines = f.read().splitlines()
346258

347-
info = {}
259+
meta = {}
348260
# Fix taken from: https://github.com/SpikeInterface/probeinterface/blob/
349261
# 19d6518fbc67daca71aba5e99d8aa0d445b75eb7/probeinterface/io.py#L649-L662
350262
for line in lines:
@@ -356,6 +268,103 @@ def read_meta_file(meta_file):
356268
# replace by the list
357269
k = k[1:]
358270
v = v[1:-1].split(')(')[1:]
359-
info[k] = v
271+
meta[k] = v
272+
273+
return meta
274+
275+
276+
def extract_stream_info(meta_file, meta):
277+
"""Extract info from the meta dict"""
278+
279+
num_chan = int(meta['nSavedChans'])
280+
281+
# Example file name structure:
282+
# Consider the filenames: `Noise4Sam_g0_t0.nidq.bin` or `Noise4Sam_g0_t0.imec0.lf.bin`
283+
# The filenames consist of 3 or 4 parts separated by `.`
284+
# 1. "Noise4Sam_g0_t0" will be the `name` variable. This choosen by the user
285+
# at recording time.
286+
# 2. "_gt0_" will give the `seg_index` (here 0)
287+
# 3. "nidq" or "imec0" will give the `device` variable
288+
# 4. "lf" or "ap" will be the `signal_kind` variable
289+
# `stream_name` variable is the concatenation of `device.signal_kind`
290+
name = Path(meta_file).stem
291+
r = re.findall(r'_g(\d*)_t', name)
292+
if len(r) == 0:
293+
# when manual renaming _g0_ can be removed
294+
seg_index = 0
295+
else:
296+
seg_index = int(r[0][0])
297+
device = name.split('.')[1]
298+
if 'imec' in device:
299+
signal_kind = name.split('.')[2]
300+
stream_name = device + '.' + signal_kind
301+
units = 'uV'
302+
# please note the 1e6 in gain for this uV
303+
304+
# metad['imroTbl'] contain two gain per channel AP and LF
305+
# except for the last fake channel
306+
per_channel_gain = np.ones(num_chan, dtype='float64')
307+
if 'imDatPrb_type' not in meta or meta['imDatPrb_type'] == '0':
308+
# This work with NP 1.0 case with different metadata versions
309+
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_3A.md#imec
310+
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_3B1.md#imec
311+
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_3B2.md#imec
312+
if signal_kind == 'ap':
313+
index_imroTbl = 3
314+
elif signal_kind == 'lf':
315+
index_imroTbl = 4
316+
for c in range(num_chan - 1):
317+
v = meta['imroTbl'][c].split(' ')[index_imroTbl]
318+
per_channel_gain[c] = 1. / float(v)
319+
gain_factor = float(meta['imAiRangeMax']) / 512
320+
channel_gains = gain_factor * per_channel_gain * 1e6
321+
elif meta['imDatPrb_type'] in ('21', '24') and signal_kind == 'ap':
322+
# This work with NP 2.0 case with different metadata versions
323+
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_20.md#channel-entries-by-type
324+
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_20.md#imec
325+
# https://github.com/billkarsh/SpikeGLX/blob/gh-pages/Support/Metadata_30.md#imec
326+
per_channel_gain[:-1] = 1 / 80.
327+
gain_factor = float(meta['imAiRangeMax']) / 8192
328+
channel_gains = gain_factor * per_channel_gain * 1e6
329+
else:
330+
raise NotImplementedError('This meta file version of spikeglx'
331+
'is not implemented')
332+
else:
333+
signal_kind = ''
334+
stream_name = device
335+
units = 'V'
336+
channel_gains = np.ones(num_chan)
337+
338+
# there are differents kinds of channels with different gain values
339+
mn, ma, xa, dw = [int(e) for e in meta['snsMnMaXaDw'].split(sep=',')]
340+
per_channel_gain = np.ones(num_chan, dtype='float64')
341+
per_channel_gain[0:mn] = 1. / float(meta['niMNGain'])
342+
per_channel_gain[mn:mn + ma] = 1. / float(meta['niMAGain'])
343+
# this scaling come from the code in this zip
344+
# https://billkarsh.github.io/SpikeGLX/Support/SpikeGLX_Datafile_Tools.zip
345+
# in file readSGLX.py line76
346+
# this is equivalent of 2**15
347+
gain_factor = float(meta['niAiRangeMax']) / 32768
348+
channel_gains = per_channel_gain * gain_factor
349+
350+
info = {}
351+
info['name'] = name
352+
info['meta'] = meta
353+
for k in ('niSampRate', 'imSampRate'):
354+
if k in meta:
355+
info['sampling_rate'] = float(meta[k])
356+
info['num_chan'] = num_chan
357+
358+
info['sample_length'] = int(meta['fileSizeBytes']) // 2 // num_chan
359+
info['seg_index'] = seg_index
360+
info['device'] = device
361+
info['signal_kind'] = signal_kind
362+
info['stream_name'] = stream_name
363+
info['units'] = units
364+
info['channel_names'] = [txt.split(';')[0] for txt in meta['snsChanMap']]
365+
info['channel_gains'] = channel_gains
366+
info['channel_offsets'] = np.zeros(info['num_chan'])
360367

361368
return info
369+
370+

0 commit comments

Comments
 (0)