playback#

Replay a saved mesofield session as if it were a live acquisition.

A playback run instantiates PlaybackCamera and PlaybackEncoder devices that read recorded OME-TIFF frames and encoder CSVs off disk and re-emit them through the standard DeviceSignals bundle. The DataManager registers them like any other producer, so the in-memory DataQueue, every subscribed processor and the GUI viewer see the data move through the same pipeline they would during a live capture.

Public surface used by mesofield playback <experiment_dir>:

Playback is read-only: devices do not allocate writers, and the procedure skips the dataqueue logger, the per-device save_data step, and the manifest.json re-write so the original session folder is left untouched.

class mesofield.playback.PlaybackClock[source]#

Bases: object

Wall-clock anchor shared by every playback device in a session.

t0_original is the earliest device timestamp across all producers in the manifest; t0_wall is captured at arm() time. Each replay thread sleeps until t0_wall + (original_ts - t0_original) / speed, which keeps the two cameras and the encoder in their original relative order.

sleep_until(original_ts, stop_event)[source]#

Block until the wall-clock moment matching original_ts.

Returns True when interrupted via stop_event.

Parameters:
Return type:

bool

__init__(t0_original=0.0, speed=1.0, t0_wall=0.0)#
Parameters:
Return type:

None

class mesofield.playback.PlaybackCamera[source]#

Bases: BaseCamera, BaseDataProducer

Replays an OME-TIFF + sidecar JSON pair through the standard camera surface.

__init__(cfg=None, **kwargs)[source]#
Parameters:
Return type:

None

arm(config)[source]#

Per-run prep: set up the writer + (optionally) an MDA sequence.

The default body fits both MMCamera (which needs a sequence) and OpenCV/Mock (where set_sequence is a no-op). Subclasses override only when they need additional prep.

Parameters:

config (ExperimentConfig)

Return type:

None

set_writer(make_path)[source]#

No-op: playback never allocates a writer.

Parameters:

make_path (Any)

Return type:

None

snap()[source]#

Capture a single frame outside any recording, return it as an ndarray.

Used by the GUI’s snap button. Implementations should NOT alter recording state – snap is preview-only – but they SHOULD call _save_snap_png() so each snap also lands a *_snap.png.

Return type:

ndarray | None

start_live()[source]#

Begin continuous live preview WITHOUT writing to disk.

Subscribers receive frames via image_ready (Qt) / signals.data (psygnal). No recording side-effects; pair with stop_live().

Return type:

None

stop_live()[source]#

End the continuous live preview started by start_live().

Return type:

None

property calibration: Dict[str, Any]#

Camera-specific constants worth recording in the AcquisitionManifest.

class mesofield.playback.PlaybackEncoder[source]#

Bases: BaseDataProducer

Replays a saved encoder/treadmill CSV through signals.data.

__init__(cfg=None, **kwargs)[source]#
Parameters:
Return type:

None

arm(config)[source]#

Default arm: clear buffer and resolve output_path.

config is expected to expose make_path(name, ext, bids) (see mesofield.config.ExperimentConfig).

Parameters:

config (ExperimentConfig)

Return type:

None

property calibration: Dict[str, Any]#

Device-specific constants worth recording with the data.

Default: everything in cfg that isn’t an orchestration key. Override on a subclass to curate the list explicitly.

class mesofield.playback.PlaybackContext[source]#

Bases: object

Bundle returned by discover_playback_context().

__init__(procedure, session_dir, speed, loop, clock, producers=<factory>)#
Parameters:
Return type:

None

class mesofield.playback.PlaybackSession[source]#

Bases: object

One (subject, session) directory discovered on disk.

Holds just enough metadata for the ConfigController dropdowns to present a choice: the parsed subject/session ids, the absolute session directory, the path to its manifest, and the task/protocol read from the manifest’s session block (used as display hints and to seed ExperimentConfig).

__init__(subject, session, session_dir, manifest_path, task=None, protocol=None)#
Parameters:
  • subject (str)

  • session (str)

  • session_dir (Path)

  • manifest_path (Path)

  • task (str | None)

  • protocol (str | None)

Return type:

None

mesofield.playback.discover_playback_context(experiment_dir, *, speed=1.0, loop=False)[source]#

Build a PlaybackContext from a recorded session directory.

Parameters:
Return type:

PlaybackContext

mesofield.playback.discover_playback_sessions(experiment_dir)[source]#

Enumerate every data/sub-*/ses-*/manifest.json under experiment_dir.

Falls back to scanning experiment_dir itself when it points directly at a session directory. Sessions are returned sorted by (subject, session) so the dropdowns have a predictable order.

Parameters:

experiment_dir (Path)

Return type:

List[PlaybackSession]

class mesofield.playback.PlaybackBrowser[source]#

Bases: object

Drives ConfigController for playback.

Two responsibilities:

  1. Re-seed ExperimentConfig.subjects from the set of recorded sessions on disk so the subject dropdown lists what is actually playable, and register the per-subject session ids as register_choices on the session key so it renders as a dropdown.

  2. When the user picks a different subject or session, tear down the current playback procedure and swap a freshly-built one into MainWindow, re-using the existing widget-rebuild path (_build_acquisition_ui + _on_config_applied).

Implementation note: the actual swap is deferred via QTimer.singleShot because the change callback fires inside a QComboBox signal handler – rebuilding the parent ConfigController during that callback would delete the QObject that emitted the signal.

__init__(main_window, sessions, *, speed=1.0, loop=False)[source]#
Parameters:
Return type:

None

mesofield.playback.launch_playback_app(context, *, browser_sessions=None)[source]#

Open the standard mesofield GUI against a PlaybackContext.

When browser_sessions is supplied, a PlaybackBrowser is wired into the MainWindow’s ConfigController so the subject/session dropdowns swap playback targets on change.

Parameters:
Return type:

int