Skip to content

Commit

Permalink
BUG: Fix video playback with other visuals (#413)
Browse files Browse the repository at this point in the history
* BUG: Allow empty load_buffer

* FIX: Fix image + drawables

* FIX: Remove comments

* FIX: Smoother

* FIX: Better screenshot

* FIX: Doc

* FIX: Simpler

* FIX: Simpler

* FIX: Fix pausing

* FIX: pop_handlers
  • Loading branch information
larsoner authored Jun 19, 2020
1 parent 62a80b2 commit 4ace255
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 28 deletions.
30 changes: 17 additions & 13 deletions examples/stimuli/advanced_video.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import numpy as np
from expyfun import (ExperimentController, fetch_data_file, building_doc,
analyze as ea)
analyze as ea, visual)

print(__doc__)

Expand All @@ -26,22 +26,32 @@
with ExperimentController(**ec_args) as ec:
screen_period = 1. / ec.estimate_screen_fs()
all_presses = list()
fix = visual.FixationDot(ec)
text = text = visual.Text(ec, "Running ...", (0, -0.1), 'k')
screenshot = None # don't have one yet
ec.load_video(movie_path)
ec.video.set_scale('fill')
ec.screen_prompt('press 1 during video to toggle pause.', max_wait=1.)
ec.listen_presses() # to catch presses on first pass of while loop
t_zero = ec.video.play()
this_sec = 0
t_zero = ec.video.play(auto_draw=False)
this_sec = 0.
while not ec.video.finished:
if ec.video.playing:
fliptime = ec.flip()
else: # to catch presses reliably, need delay between loop executions
ec.wait_secs(screen_period / 5)
ec.video.draw()
else:
ec.screen_text('paused!', color='y', font_size=32, wrap=False)
text.draw()
fix.draw()
if screenshot is None:
screenshot = ec.screenshot()
fliptime = ec.flip()
presses = ec.get_presses(live_keys=[1], relative_to=t_zero)
ec.listen_presses()
# change the background color every 1 second
if this_sec != int(ec.video.time):
this_sec = int(ec.video.time)
text = visual.Text(
ec, str(colors[this_sec]), (0, -0.1), 'k')
ec.set_background_color(colors[this_sec])
# shrink the video, then move it rightward
if ec.video.playing:
Expand All @@ -54,15 +64,9 @@
all_presses.extend(presses)
if len(presses) % 2: # if even number of presses, do nothing
if ec.video.playing:
ec.video.set_visible(False)
ec.video.pause()
ec.screen_text('pause!', color='k', font_size=32,
wrap=False)
ec.flip()
else:
ec.video.set_visible(True)
ec.video.play()
screenshot = ec.screenshot()
ec.video.play(auto_draw=False)
if building_doc:
break
ec.delete_video()
Expand Down
11 changes: 6 additions & 5 deletions expyfun/_experiment_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -1775,7 +1775,7 @@ def _validate_audio(self, samples):
samples = np.asarray(samples, dtype=np.float32)

# check values
if np.max(np.abs(samples)) > 1:
if samples.size and np.max(np.abs(samples)) > 1:
raise ValueError('Sound data exceeds +/- 1.')
# samples /= np.max(np.abs(samples),axis=0)

Expand All @@ -1795,12 +1795,13 @@ def _validate_audio(self, samples):
logger.warning('Expyfun: Resampling {} seconds of audio'
''.format(round(len(samples) / self.stim_fs, 2)))
from mne.filter import resample
samples = resample(
samples.astype(np.float64), self.fs, self.stim_fs,
axis=0).astype(np.float32)
if samples.size:
samples = resample(
samples.astype(np.float64), self.fs, self.stim_fs,
axis=0).astype(np.float32)

# check RMS
if self._check_rms is not None:
if self._check_rms is not None and samples.size:
chans = [samples[:, x] for x in range(samples.shape[1])]
if self._check_rms == 'wholefile':
chan_rms = [np.sqrt(np.mean(x ** 2)) for x in chans]
Expand Down
7 changes: 6 additions & 1 deletion expyfun/_eyelink_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,7 +779,12 @@ def on_key_press(symbol, modifiers):
on_mouse_drag)

def release_event_handlers(self):
self.ec.window.pop_handlers() # should detacch top-level handler
try:
fun = self.ec.window.pop_handlers
except AttributeError:
pass # Pyglet bug?
else:
fun() # should detach top-level handler
del self.label
del self.img

Expand Down
1 change: 1 addition & 0 deletions expyfun/tests/test_experiment_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ def test_ec(ac, hide_window):
# test buffer data handling
ec.set_rms_checking(None)
ec.load_buffer([0, 0, 0, 0, 0, 0])
ec.load_buffer([])
pytest.raises(ValueError, ec.load_buffer, [0, 2, 0, 0, 0, 0])
ec.load_buffer(np.zeros((100,)))
with pytest.raises(ValueError, match='100 did not match .* count 2'):
Expand Down
29 changes: 20 additions & 9 deletions expyfun/visual/_visual.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def __init__(self, ec, text, pos=(0, 0), color='white',
elif isinstance(width, string_types):
raise ValueError('"width", if str, must be "auto"')
self._attr = attr
text = text + '\n ' # weird Pyglet bug
if wrap:
text = text + '\n ' # weird Pyglet bug
if self._attr:
preamble = ('{{font_name \'{}\'}}{{font_size {}}}{{color {}}}'
'').format(font_name, font_size, _convert_color(color))
Expand Down Expand Up @@ -320,7 +321,7 @@ def set_line_width(self, line_width):
self._line_width = line_width

def draw(self):
"""Draw the object to the display buffer"""
"""Draw the object to the display buffer."""
gl.glUseProgram(self._program)
for kind in ('fill', 'line'):
if self._counts[kind] > 0:
Expand Down Expand Up @@ -796,7 +797,7 @@ def set_color(self, color, idx):
self._circles[idx].set_fill_color(color)

def set_colors(self, colors):
"""Set the color of each circle
"""Set the color of each circle.
Parameters
----------
Expand All @@ -811,8 +812,7 @@ def set_colors(self, colors):
self.set_color(color, idx)

def draw(self):
"""Draw the fixation dot
"""
"""Draw the fixation dot."""
for circle in self._circles:
circle.draw()

Expand Down Expand Up @@ -1112,17 +1112,23 @@ def __init__(self, ec, file_name, pos=(0, 0), units='norm', scale=1.,
self._visible = visible
self._eos_fun = self._eos_new if _new_pyglet() else self._eos_old

def play(self):
def play(self, auto_draw=True):
"""Play video from current position.
Parameters
----------
auto_draw : bool
If True, add ``self.draw`` to ``ec.on_every_flip``.
Returns
-------
time : float
The timestamp (on the parent ``ExperimentController`` timeline) at
which ``play()`` was called.
"""
if not self._playing:
self._ec.call_on_every_flip(self.draw)
if auto_draw:
self._ec.call_on_every_flip(self.draw)
self._player.play()
self._playing = True
else:
Expand All @@ -1140,8 +1146,12 @@ def pause(self):
which ``pause()`` was called.
"""
if self._playing:
idx = self._ec.on_every_flip_functions.index(self.draw)
self._ec.on_every_flip_functions.pop(idx)
try:
idx = self._ec.on_every_flip_functions.index(self.draw)
except ValueError: # not auto_draw
pass
else:
self._ec.on_every_flip_functions.pop(idx)
self._player.pause()
self._playing = False
else:
Expand Down Expand Up @@ -1216,6 +1226,7 @@ def set_pos(self, pos, units='norm', center=True):
def _draw(self):
self._texture = self._player.get_texture()
self._scale_texture()
gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
self._texture.blit(*self._actual_pos)

def draw(self):
Expand Down

0 comments on commit 4ace255

Please sign in to comment.