From e8817c06bd8781b91d5d6a8e9054c6288dde3648 Mon Sep 17 00:00:00 2001 From: Stefan Appelhoff Date: Mon, 4 Nov 2024 20:09:16 +0100 Subject: [PATCH] FIX: Not looping leading to TypeError (#119) --- CHANGELOG.md | 2 ++ pyxdf/cli/playback_lsl.py | 27 +++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7e67bc..06c6d0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ ## [UNRELEASED] - YYYY-MM-DD ### Fixed - Expose detected segment (used in dejittering) as `stream["info"]["segments"]` ([#117](https://github.com/xdf-modules/pyxdf/pull/117) by [Robert Guggenberger](https://github.com/agricolab)) +- A non-looping playback of an XDF file will no longer lead to a `TypeError` ([#119](https://github.com/xdf-modules/pyxdf/pull/119) by [Stefan Appelhoff](https://github.com/sappelhoff)) ### Changed - Rename `pyxdf.examples` module to `pyxdf.cli` ([#118](https://github.com/xdf-modules/xdf-Python/pull/118) by [Clemens Brunner](https://github.com/cbrnr)) +- Reverse logic of `--loop` argument in `pyxdf.examples.playback_lsl.py` to be more in line with standard practice: Supplying `--loop` will loop, whereas ommitting `--loop` will NOT loop ([#119](https://github.com/xdf-modules/pyxdf/pull/119) by [Stefan Appelhoff](https://github.com/sappelhoff)) ## [1.16.8] - 2024-07-18 ### Fixed diff --git a/pyxdf/cli/playback_lsl.py b/pyxdf/cli/playback_lsl.py index 5bf1e1d..5409213 100644 --- a/pyxdf/cli/playback_lsl.py +++ b/pyxdf/cli/playback_lsl.py @@ -100,7 +100,7 @@ def update(self): # Previous iteration ended at the file boundary; wrap around and reset. self._prev_file_read_s = 0.0 self._n_loop += 1 - overrun = self._n_loop * self._boundary + overrun = self._n_loop * self._boundary if self._boundary else 0 self._file_read_s = _file_read_s - overrun if self._boundary and self._file_read_s >= self._boundary: # Previous was below boundary, now above boundary. @@ -133,7 +133,7 @@ def sleep(self, duration: Optional[float] = None) -> None: def main( fname: str, playback_speed: float = 1.0, - loop: bool = True, + loop: bool = False, wait_for_consumer: bool = False, ): streams, _ = pyxdf.load_xdf(fname) @@ -192,10 +192,12 @@ def main( continue timer.update() t_start, t_stop = timer.step_range + all_streams_exhausted = True for streamer in streamers: start_idx = read_heads[streamer.name] if t_start > 0 else 0 stop_idx = np.searchsorted(streamer.tvec, t_stop) if stop_idx > start_idx: + all_streams_exhausted = False if streamer.srate > 0: sl = np.s_[start_idx:stop_idx] push_dat = streams[streamer.stream_ix]["time_series"][sl] @@ -210,22 +212,35 @@ def main( ) # print(f"Pushed sample: {sample}") read_heads[streamer.name] = stop_idx + + if not loop and all_streams_exhausted: + print("Playback finished.") + break timer.sleep() except KeyboardInterrupt: - print("TODO: Shutdown outlets") + print("Keyboard interrupt received. Deleting outlets...") + for streamer in streamers: + del streamer.outlet + print("Shutdown complete.") if __name__ == "__main__": parser = argparse.ArgumentParser( description="Playback an XDF file over LSL streams." ) - parser.add_argument("filename", type=str, help="Path to the XDF file") + parser.add_argument("filename", type=str, help="Path to the XDF file.") parser.add_argument( "--playback_speed", type=float, default=1.0, help="Playback speed multiplier." ) - parser.add_argument("--loop", action="store_false") - parser.add_argument("--wait_for_consumer", action="store_true") + parser.add_argument( + "--loop", action="store_true", help="Loop playback of the file." + ) + parser.add_argument( + "--wait_for_consumer", + action="store_true", + help="Wait for consumer before starting playback.", + ) args = parser.parse_args() main( args.filename,