Repository: SpikeInterface/spikeextractors

Issue:
CEDExtractor traces are missing the last element
The trace array imported from an smrx file using CEDExtractor has one element less than when the same file is imported directly with sonpy

Discussion:

Patch:
diff --git a/spikeextractors/extractors/cedextractors/cedrecordingextractor.py b/spikeextractors/extractors/cedextractors/cedrecordingextractor.py
index 7cb2444..b563707 100644
--- a/spikeextractors/extractors/cedextractors/cedrecordingextractor.py
+++ b/spikeextractors/extractors/cedextractors/cedrecordingextractor.py
@@ -149,7 +149,7 @@ class CEDRecordingExtractor(RecordingExtractor):
         num_frames: int
             Number of frames in the recording (duration of recording)
         """
-        return int(self._channel_smrxinfo[0]['max_time'] / self._channel_smrxinfo[0]['divide'] - self._channel_smrxinfo[0]['frame_offset'])
+        return 1 + int(self._channel_smrxinfo[0]['max_time'] / self._channel_smrxinfo[0]['divide'] - self._channel_smrxinfo[0]['frame_offset'])
 
     def get_sampling_frequency(self):
         """This function returns the sampling frequency in units of Hz.
diff --git a/spikeextractors/extractors/cedextractors/utils.py b/spikeextractors/extractors/cedextractors/utils.py
index 2a88ac7..6495634 100644
--- a/spikeextractors/extractors/cedextractors/utils.py
+++ b/spikeextractors/extractors/cedextractors/utils.py
@@ -32,7 +32,7 @@ def get_channel_info(f, smrx_ch_ind):
         Index of smrx channel. Does not match necessarily with extractor id.
     """
 
-    nMax = int(f.ChannelMaxTime(smrx_ch_ind) / f.ChannelDivide(smrx_ch_ind))
+    nMax = 1 + int(f.ChannelMaxTime(smrx_ch_ind) / f.ChannelDivide(smrx_ch_ind))
     frame_offset = f.FirstTime(chan=smrx_ch_ind, tFrom=0, tUpto=nMax) / f.ChannelDivide(smrx_ch_ind)
     ch_info = {
         'type': f.ChannelType(smrx_ch_ind),           # Get the channel kind
@@ -72,9 +72,9 @@ def get_channel_data(f, smrx_ch_ind, start_frame=0, end_frame=None):
     """
 
     if end_frame is None:
-        end_frame = int(f.ChannelMaxTime(smrx_ch_ind) / f.ChannelDivide(smrx_ch_ind))
+        end_frame = 1 + int(f.ChannelMaxTime(smrx_ch_ind) / f.ChannelDivide(smrx_ch_ind))
 
-    nMax = int(f.ChannelMaxTime(smrx_ch_ind) / f.ChannelDivide(smrx_ch_ind))
+    nMax = 1 + int(f.ChannelMaxTime(smrx_ch_ind) / f.ChannelDivide(smrx_ch_ind))
     frame_offset = int(f.FirstTime(chan=smrx_ch_ind, tFrom=0, tUpto=nMax) / f.ChannelDivide(smrx_ch_ind))
     start_frame += frame_offset
     end_frame += frame_offset


Test patch:
diff --git a/tests/test_extractors.py b/tests/test_extractors.py
index 506d504..1142d1d 100644
--- a/tests/test_extractors.py
+++ b/tests/test_extractors.py
@@ -5,6 +5,7 @@ import unittest
 from pathlib import Path
 
 import numpy as np
+from sonpy import lib as sp
 
 import spikeextractors as se
 from spikeextractors.exceptions import NotDumpableExtractorError
@@ -323,6 +324,18 @@ class TestExtractors(unittest.TestCase):
         check_recordings_equal(self.RX, RX_biocam)
         check_dumping(RX_biocam)
 
+    def test_ced_extractor(self):
+        n_elements = 881
+        trace_out = np.arange(0, n_elements, dtype=np.short)
+        assert len(trace_out) == n_elements
+        smrx_file = sp.SonFile('test.smrx')
+        smrx_file.SetWaveChannel(0, 7, sp.DataType.Adc)
+        smrx_file.WriteInts(0, trace_out, 0)
+        del smrx_file
+        recording = se.CEDRecordingExtractor('test.smrx', smrx_channel_ids=[0])
+        trace_in = recording.get_traces([0])[0]
+        assert len(trace_in) == n_elements
+
     def test_mearec_extractors(self):
         path1 = self.test_dir + '/raw.h5'
         se.MEArecRecordingExtractor.write_recording(self.RX, path1)