Skip to content

Commit dd7b799

Browse files
authored
Merge pull request #2 from drammock/api_brainstorming
notes from brainstorming mtg
2 parents b75639a + e93d39b commit dd7b799

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import mne
2+
3+
from ilabs_streamsync import StreamSync, extract_audio_from_video
4+
5+
# load an MNE raw file
6+
raw = None
7+
cam1 = None
8+
flux1 = None
9+
my_events = []
10+
11+
12+
subjects = ["146a", "222b"]
13+
14+
for subj in subjects:
15+
# construct the filename/path
16+
# load the Raw
17+
# figure out where video files are & load them
18+
audio1 = extract_audio_from_video(cam1)
19+
20+
ss = StreamSync(raw, "STIM001")
21+
ss.add_stream(audio1)
22+
ss.add_camera_events(my_events)
23+
ss.add_stream(flux1)
24+
result = ss.do_syncing()
25+
fig = ss.plot_sync()
26+
annot = ss.add_camera_events(my_events)
27+
raw.set_annotations(annot)
28+
fig.savefig(...)
29+
if result < 0.7:
30+
write_log_msg(f"subj {subj} had bad pulse syncing, aborting")
31+
continue
32+
33+
# apply maxfilter
34+
# do ICA

src/ilabs_streamsync/streamsync.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,47 @@
11
class StreamSync:
2-
def __init__(self):
2+
"""Synchronize two data streams.
3+
4+
Inputs: `mne.io.Raw` files, audio files (TODO which formats?),
5+
and additional camera events.
6+
7+
Outputs: `mne.Annotations` object created from the camera events and
8+
time-warped to the timescale of the `Raw`.
9+
"""
10+
11+
def __init__(self, reference_object, pulse_channel):
12+
self.ref_stream = reference_object.get_chan(pulse_channel)
13+
self.sfreq = reference_object.info["sfreq"] # Hz
14+
self.streams = []
15+
16+
def add_stream(self, stream, channel=None, events=None):
17+
"""Add a new ``Raw`` or video stream, optionally with events.
18+
19+
stream : Raw | wav
20+
An audio or FIF stream.
21+
channel : str | int | None
22+
Which channel of `stream` contains the sync pulse sequence.
23+
events : array-like | None
24+
Events associated with the stream. TODO: should they be integer sample
25+
numbers? Timestamps? Do we support both?
26+
"""
27+
pulses = self._extract_pulse_sequence_from_stream(stream, channel=channel)
28+
self.streams.append(pulses)
29+
30+
def _extract_pulse_sequence_from_stream(self, stream, channel):
31+
# TODO triage based on input type (e.g., if it's a Raw, pull out a stim chan,
32+
# if it's audio, just add it as-is)
333
pass
34+
35+
def do_syncing(self):
36+
"""Synchronize all streams with the reference stream."""
37+
# TODO (waves hands) do the hard part.
38+
# TODO spit out a report of correlation/association between all pairs of streams
39+
pass
40+
41+
def plot_sync(self):
42+
pass
43+
44+
45+
def extract_audio_from_video(path_to_video, channel):
46+
"""Path can be a regex or glob to allow batch processing."""
47+
pass

0 commit comments

Comments
 (0)