psychopy 2024.2.1__py3-none-any.whl → 2024.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of psychopy might be problematic. Click here for more details.
- psychopy/.DS_Store +0 -0
- psychopy/GIT_SHA +1 -1
- psychopy/VERSION +1 -1
- psychopy/__init__.py +10 -1
- psychopy/__init__.py.orig +65 -0
- psychopy/app/{locale/ar_001/.DS_Store → .DS_Store} +0 -0
- psychopy/app/Resources/.DS_Store +0 -0
- psychopy/app/_psychopyApp.py +11 -3
- psychopy/app/appData.spec +1 -1
- psychopy/app/builder/builder.py +1 -1
- psychopy/app/builder/builder.py.orig +3932 -0
- psychopy/app/builder/dialogs/__init__.py.orig +1679 -0
- psychopy/app/builder/dialogs/paramCtrls.py +1 -1
- psychopy/app/builder/dialogs/paramCtrls.py.orig +713 -0
- psychopy/app/colorpicker/__init__.py.orig +411 -0
- psychopy/app/cortex.log +0 -0
- psychopy/app/jobs.py +8 -1
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +2452 -1731
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN.po +6127 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/zh_CN_allFlagged.po +7366 -0
- psychopy/app/plugin_manager/dialog.py +9 -7
- psychopy/app/ribbon.py +2 -1
- psychopy/app/runner/runner.py +7 -5
- psychopy/clock.py +8 -4
- psychopy/core.py.orig +169 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/index.html +23 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks-legacy-browsers.js +423 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/randomisedBlocks.js +427 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/chooseBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/facesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/housesBlock.xlsx +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/face03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house01.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house02.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/html/resources/stims/house03.jpg +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.py +330 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +330 -0
- psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xml +298 -0
- psychopy/demos/builder/Feature Demos/eyetracking/eyetracking.xsd +120 -0
- psychopy/demos/builder/Tools/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +38 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +3418 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +2 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +15 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.psyexp +323 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual.py +562 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +562 -0
- psychopy/demos/builder/Tools/gammaCalibration/questStairs.xlsx +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/readme.md +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/low_contrast.png +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/make_2nd_order_tex.py +59 -0
- psychopy/demos/builder/Tools/gammaCalibration/resources/second_order_tex.png +0 -0
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
- psychopy/demos/coder/iohub/.iohpid +1 -0
- psychopy/demos/coder/iohub/eyetracking/.iohpid +1 -0
- psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/radialGratingContracting.py +29 -0
- psychopy/experiment/_experiment.py.orig +1032 -0
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/_base.py +13 -4
- psychopy/experiment/components/_base.py.orig +823 -0
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py +10 -1
- psychopy/experiment/components/microphone/__init__.py.orig +490 -0
- psychopy/experiment/components/polygon/__init__.py +21 -22
- psychopy/experiment/components/settings/__init__.py +13 -14
- psychopy/experiment/components/settings/__init__.py.orig +1337 -0
- psychopy/experiment/components/textbox/__init__.py.orig +310 -0
- psychopy/experiment/components/webcam/.DS_Store +0 -0
- psychopy/experiment/components/webcam/light/.DS_Store +0 -0
- psychopy/experiment/flow.py +10 -8
- psychopy/experiment/loops.py.orig +829 -0
- psychopy/experiment/params.py +8 -3
- psychopy/experiment/params.py.orig +408 -0
- psychopy/experiment/routine.py.orig +503 -0
- psychopy/experiment/routines/_base.py +15 -6
- psychopy/experiment/routines/counterbalance/__init__.py +1 -0
- psychopy/gui/qtgui.py +14 -7
- psychopy/gui/util.py +10 -14
- psychopy/gui/wxgui.py +10 -4
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/brainproducts.py.orig +680 -0
- psychopy/hardware/iolab.py.orig +238 -0
- psychopy/hardware/manager.py +1 -1
- psychopy/hardware/photodiode.py +59 -27
- psychopy/hardware/serialport.py +51 -0
- psychopy/hardware/speaker.py +4 -4
- psychopy/iohub/datastore/__init__.py.orig +443 -0
- psychopy/iohub/datastore/util.py.orig +692 -0
- psychopy/iohub/devices/mouse/darwin.py.orig +427 -0
- psychopy/iohub/devices/mouse/linux2.py.orig +198 -0
- psychopy/preferences/.DS_Store +0 -0
- psychopy/projects/pavlovia.py +10 -3
- psychopy/projects/pavlovia.py.orig +1295 -0
- psychopy/sound/backend_ptb.py +22 -5
- psychopy/sound/transcribe.py +24 -4
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestCircle_fill_local.png +0 -0
- psychopy/tests/data/__test.png +0 -0
- psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
- psychopy/tests/data/aperture1_norm_local.png +0 -0
- psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_height_local.png +0 -0
- psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_norm_local.png +0 -0
- psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
- psychopy/tests/data/blend_add_height_local.png +0 -0
- psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
- psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
- psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
- psychopy/tests/data/blend_add_norm_local.png +0 -0
- psychopy/tests/data/blend_add_stencil_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
- psychopy/tests/data/circleHex_height_local.png +0 -0
- psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
- psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
- psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
- psychopy/tests/data/circleHex_norm_local.png +0 -0
- psychopy/tests/data/circleHex_stencil_local.png +0 -0
- psychopy/tests/data/color_comparison_local.png +0 -0
- psychopy/tests/data/corrFullRandom_local.csv +16 -0
- psychopy/tests/data/corrFullRandom_local.tsv +6 -0
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/dots_height_local.png +0 -0
- psychopy/tests/data/dots_normAddBlend_local.png +0 -0
- psychopy/tests/data/dots_normHexbackground_local.png +0 -0
- psychopy/tests/data/dots_normNoShade_local.png +0 -0
- psychopy/tests/data/dots_norm_local.png +0 -0
- psychopy/tests/data/dots_stencil_local.png +0 -0
- psychopy/tests/data/elarray1_height_local.png +0 -0
- psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
- psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
- psychopy/tests/data/elarray1_norm_local.png +0 -0
- psychopy/tests/data/elarray1_stencil_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
- psychopy/tests/data/gabor1_height_local.png +0 -0
- psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
- psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
- psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
- psychopy/tests/data/gabor1_norm_local.png +0 -0
- psychopy/tests/data/gabor1_stencil_local.png +0 -0
- psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_height_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
- psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
- psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
- psychopy/tests/data/movFrame1_stencil_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/numpyImage_height_local.png +0 -0
- psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
- psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
- psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
- psychopy/tests/data/numpyImage_norm_local.png +0 -0
- psychopy/tests/data/numpyImage_stencil_local.png +0 -0
- psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
- psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
- psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
- psychopy/tests/data/shape2_1_norm_local.png +0 -0
- psychopy/tests/data/shape2_1_stencil_local.png +0 -0
- psychopy/tests/data/testLoopsBlocks.psyexp_local.py +328 -0
- psychopy/tests/data/text1_height_local.png +0 -0
- psychopy/tests/data/text1_normAddBlend_local.png +0 -0
- psychopy/tests/data/text1_normHexbackground_local.png +0 -0
- psychopy/tests/data/text1_norm_local.png +0 -0
- psychopy/tests/data/text1_stencil_local.png +0 -0
- psychopy/tests/data/text2_height.png +0 -0
- psychopy/tests/data/text2_normAddBlend.png +0 -0
- psychopy/tests/data/text2_normHexbackground.png +0 -0
- psychopy/tests/data/text2_stencil.png +0 -0
- psychopy/tests/data/wedge1_height_local.png +0 -0
- psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
- psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
- psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
- psychopy/tests/data/wedge1_norm_local.png +0 -0
- psychopy/tests/data/wedge1_stencil_local.png +0 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.csv +9 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +177 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.csv +9 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +168 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
- psychopy/tests/test_data/.DS_Store +0 -0
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +68 -0
- psychopy/tests/test_tools/test_arraytools.py +112 -0
- psychopy/tests/test_visual/test_image.py.orig +219 -0
- psychopy/tools/arraytools.py +47 -0
- psychopy/tools/versionchooser.py +1 -1
- psychopy/visual/backends/pygletbackend.py +26 -8
- psychopy/visual/basevisual.py.orig +1723 -0
- psychopy/visual/form.py.orig +1181 -0
- psychopy/visual/text.py.orig +752 -0
- psychopy/visual/textbox2/textbox2.py.orig +1315 -0
- psychopy/visual/window.py +13 -5
- psychopy/visual/windowwarp.py.orig +463 -0
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/METADATA +9 -9
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/RECORD +244 -78
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/WHEEL +1 -1
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/entry_points.txt +2 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy-2024.2.1.dist-info/licenses/AUTHORS.md +0 -138
- /psychopy/{app/locale/ar_001/LC_MESSAGE → demos/builder}/.DS_Store +0 -0
- /psychopy/{app/locale/es_ES/LC_MESSAGE → demos/builder/Experiments}/.DS_Store +0 -0
- /psychopy/{visual → demos/builder/Tools/gammaCalibration/data}/.DS_Store +0 -0
- {psychopy-2024.2.1.dist-info → psychopy-2024.2.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
|
|
2
|
+
"""The `ioLab python library
|
|
3
|
+
<http://github.com/ioLab/python-ioLabs>`_ is now defunct and the company
|
|
4
|
+
no longer trades
|
|
5
|
+
"""
|
|
6
|
+
<<<<<<< Updated upstream
|
|
7
|
+
# This file can't be named ioLabs.py, otherwise "import ioLabs" doesn't work.
|
|
8
|
+
# And iolabs.py (lowercase) did not solve it either, something is case
|
|
9
|
+
# insensitive somewhere
|
|
10
|
+
|
|
11
|
+
from numpy import ubyte
|
|
12
|
+
from psychopy import core, event, logging
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
import ioLabs
|
|
16
|
+
from ioLabs import USBBox, REPORT, COMMAND
|
|
17
|
+
except ImportError:
|
|
18
|
+
err = """Failed to import the ioLabs library. If you're using your own
|
|
19
|
+
copy of python (not the Standalone distribution of PsychoPy) then
|
|
20
|
+
try installing it with:
|
|
21
|
+
> pip install ioLabs""".replace(' ', '')
|
|
22
|
+
logging.error(err)
|
|
23
|
+
|
|
24
|
+
from psychopy.constants import PRESSED, RELEASED
|
|
25
|
+
btn2str = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7',
|
|
26
|
+
64: 'voice'}
|
|
27
|
+
|
|
28
|
+
# hack to fake a USBBox on ubuntu during documentation
|
|
29
|
+
import sys
|
|
30
|
+
if 'sphinx' in sys.modules:
|
|
31
|
+
USBBox = object
|
|
32
|
+
|
|
33
|
+
class ButtonBox(USBBox):
|
|
34
|
+
"""PsychoPy's interface to ioLabs.USBBox. Voice key completely untested.
|
|
35
|
+
|
|
36
|
+
Original author: Jonathan Roberts
|
|
37
|
+
PsychoPy rewrite: Jeremy Gray, 2013
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self):
|
|
41
|
+
"""Class to detect and report
|
|
42
|
+
`ioLab button box <http://www.iolab.co.uk>`_.
|
|
43
|
+
|
|
44
|
+
The ioLabs library needs to be installed. It is included in the
|
|
45
|
+
*Standalone* distributions of PsychoPy as of version 1.62.01.
|
|
46
|
+
Otherwise try "pip install ioLabs"
|
|
47
|
+
|
|
48
|
+
Usage::
|
|
49
|
+
|
|
50
|
+
from psychopy.hardware import iolab
|
|
51
|
+
bbox = iolab.ButtonBox()
|
|
52
|
+
|
|
53
|
+
For examples see the demos menu of the PsychoPy Coder or go to the
|
|
54
|
+
URL above.
|
|
55
|
+
|
|
56
|
+
All times are reported in units of seconds.
|
|
57
|
+
"""
|
|
58
|
+
ioLabs.USBBox.__init__(self)
|
|
59
|
+
logging.debug('init iolabs bbox')
|
|
60
|
+
self.events = []
|
|
61
|
+
self.status = None # helps Builder
|
|
62
|
+
self._lastReset = 0.0 # time on baseclock when bbox clock was reset
|
|
63
|
+
self._baseclock = core.Clock() # for basetime, not RT time
|
|
64
|
+
self.resetClock(log=True) # internal clock on the bbox
|
|
65
|
+
msg = 'button box resetClock(log=True) took %.4fs'
|
|
66
|
+
logging.exp(msg % self._baseclock.getTime())
|
|
67
|
+
|
|
68
|
+
self.commands.add_callback(REPORT.KEYDN, self._onKeyDown)
|
|
69
|
+
self.commands.add_callback(REPORT.KEYUP, self._onKeyUp)
|
|
70
|
+
self.commands.add_callback(REPORT.RTCREP, self._onRtcRep)
|
|
71
|
+
|
|
72
|
+
# set up callbacks for key events ("key" = button and or voice key):
|
|
73
|
+
def _onKey(self, report):
|
|
74
|
+
report.rt = report.rtc / 1000.
|
|
75
|
+
report.btn = report.key_code # int
|
|
76
|
+
report.key = btn2str[report.key_code] # str
|
|
77
|
+
self.events.append(report)
|
|
78
|
+
|
|
79
|
+
def _onKeyDown(self, report):
|
|
80
|
+
report.direction = PRESSED
|
|
81
|
+
self._onKey(report)
|
|
82
|
+
|
|
83
|
+
def _onKeyUp(self, report):
|
|
84
|
+
report.direction = RELEASED
|
|
85
|
+
self._onKey(report)
|
|
86
|
+
|
|
87
|
+
def _onRtcRep(self, report):
|
|
88
|
+
# read internal clock without needing a button-press; not working
|
|
89
|
+
report.rt = self.commands.rtcget()['rtc'] / 1000.
|
|
90
|
+
|
|
91
|
+
def __del__(self):
|
|
92
|
+
# does not seem to ever get called
|
|
93
|
+
self.standby()
|
|
94
|
+
for rep in [REPORT.KEYDN, REPORT.KEYUP, REPORT.RTCREP]:
|
|
95
|
+
self.remove_callback(rep)
|
|
96
|
+
ioLabs.USBBox.__del__(self)
|
|
97
|
+
|
|
98
|
+
def standby(self):
|
|
99
|
+
"""Disable all buttons and lights.
|
|
100
|
+
"""
|
|
101
|
+
self.buttons.enabled = 0x00 # 8 bit pattern 0=disabled 1=enabled
|
|
102
|
+
self.leds.state = 0xFF # leds == port2 == lights, 8 bits 0=on 1=off
|
|
103
|
+
return self
|
|
104
|
+
|
|
105
|
+
def resetClock(self, log=True):
|
|
106
|
+
"""Reset the clock on the bbox internal clock, e.g., at the start
|
|
107
|
+
of a trial.
|
|
108
|
+
|
|
109
|
+
~1ms for me; logging is much faster than the reset
|
|
110
|
+
"""
|
|
111
|
+
# better / faster than self.reset_clock() (no wait for report):
|
|
112
|
+
self.commands.resrtc()
|
|
113
|
+
self._lastReset = self._baseclock.getTime()
|
|
114
|
+
if log:
|
|
115
|
+
msg = 'reset bbox internal clock at basetime = %.3f'
|
|
116
|
+
logging.exp(msg % self._lastReset)
|
|
117
|
+
|
|
118
|
+
def _getTime(self, log=False):
|
|
119
|
+
"""Return the time on the bbox internal clock, relative to last reset.
|
|
120
|
+
|
|
121
|
+
Status: rtcget() not working
|
|
122
|
+
|
|
123
|
+
`log=True` will log the bbox time and elapsed CPU (python) time.
|
|
124
|
+
"""
|
|
125
|
+
bboxTime = self.commands.rtcget()['rtc'] / 1000.
|
|
126
|
+
logging.debug('bbox rtc: %.3f' % bboxTime)
|
|
127
|
+
if log:
|
|
128
|
+
cpuTime = self._baseclock.getTime() - self._lastReset
|
|
129
|
+
logging.debug('cpu time: %.3f' % cpuTime)
|
|
130
|
+
|
|
131
|
+
return bboxTime
|
|
132
|
+
|
|
133
|
+
def getBaseTime(self):
|
|
134
|
+
"""Return the time since init (using the CPU clock, not ioLab bbox).
|
|
135
|
+
|
|
136
|
+
Aim is to provide a similar API as for a Cedrus box.
|
|
137
|
+
Could let both clocks run for a long time to assess relative drift.
|
|
138
|
+
"""
|
|
139
|
+
return self._baseclock.getTime()
|
|
140
|
+
|
|
141
|
+
def setEnabled(self, buttonList=(0, 1, 2, 3, 4, 5, 6, 7), voice=False):
|
|
142
|
+
"""Set a filter to suppress events from non-enabled buttons.
|
|
143
|
+
|
|
144
|
+
The ioLabs bbox filters buttons in hardware; here we just tell it
|
|
145
|
+
what we want:
|
|
146
|
+
None - disable all buttons
|
|
147
|
+
an integer (0..7) - enable a single button
|
|
148
|
+
a list of integers (0..7) - enable all buttons in the list
|
|
149
|
+
|
|
150
|
+
Set voice=True to enable the voiceKey - gets reported as button 64
|
|
151
|
+
"""
|
|
152
|
+
allInRange = all([b in range(8) for b in buttonList])
|
|
153
|
+
if not (buttonList is None or allInRange):
|
|
154
|
+
raise ValueError('buttonList needs to be a list of 0..7, or None')
|
|
155
|
+
self.buttons.enabled = _list2bits(buttonList)
|
|
156
|
+
self.int0.enabled = int(voice)
|
|
157
|
+
|
|
158
|
+
def getEnabled(self):
|
|
159
|
+
"""Return a list of the buttons that are currently enabled.
|
|
160
|
+
"""
|
|
161
|
+
return _bits2list(self.buttons.enabled)
|
|
162
|
+
|
|
163
|
+
def setLights(self, lightList=(0, 1, 2, 3, 4, 5, 6, 7)):
|
|
164
|
+
"""Turn on the specified LEDs (None, 0..7, list of 0..7)
|
|
165
|
+
"""
|
|
166
|
+
self.leds.state = ~_list2bits(lightList)
|
|
167
|
+
|
|
168
|
+
def waitEvents(self, downOnly=True, timeout=0, escape='escape',
|
|
169
|
+
wait=0.002):
|
|
170
|
+
"""Wait for and return the first button press event.
|
|
171
|
+
|
|
172
|
+
Always calls `clearEvents()` first (like PsychoPy keyboard waitKeys).
|
|
173
|
+
|
|
174
|
+
Use `downOnly=False` to include button-release events.
|
|
175
|
+
|
|
176
|
+
`escape` is a list/tuple of keyboard events that, if pressed, will
|
|
177
|
+
interrupt the bbox wait; `waitKeys` will return `None` in that case.
|
|
178
|
+
|
|
179
|
+
`timeout` is the max time to wait in seconds before returning `None`.
|
|
180
|
+
`timeout` of 0 means no time-out (= default).
|
|
181
|
+
"""
|
|
182
|
+
self.clearEvents() # e.g., removes UP from previous DOWN
|
|
183
|
+
if timeout > 0:
|
|
184
|
+
c = core.Clock()
|
|
185
|
+
if escape and not type(escape) in [list, tuple]:
|
|
186
|
+
escape = [escape]
|
|
187
|
+
while True:
|
|
188
|
+
if wait:
|
|
189
|
+
core.wait(wait, 0) # throttle CPU; event RTs come from bbox
|
|
190
|
+
evt = self.getEvents(downOnly=downOnly)
|
|
191
|
+
if evt:
|
|
192
|
+
evt = evt[0]
|
|
193
|
+
break
|
|
194
|
+
if escape and event.getKeys(escape) or 0 < timeout < c.getTime():
|
|
195
|
+
return
|
|
196
|
+
return evt
|
|
197
|
+
|
|
198
|
+
def getEvents(self, downOnly=True):
|
|
199
|
+
"""Detect and return a list of all events (likely just one); no block.
|
|
200
|
+
|
|
201
|
+
Use `downOnly=False` to include button-release events.
|
|
202
|
+
"""
|
|
203
|
+
if downOnly is False:
|
|
204
|
+
raise NotImplementedError()
|
|
205
|
+
self.process_received_reports()
|
|
206
|
+
evts = []
|
|
207
|
+
for evt in self.events:
|
|
208
|
+
if evt.direction == PRESSED or not downOnly:
|
|
209
|
+
evts.append(evt)
|
|
210
|
+
return evts
|
|
211
|
+
|
|
212
|
+
def clearEvents(self):
|
|
213
|
+
"""Discard all button / voice key events.
|
|
214
|
+
"""
|
|
215
|
+
self.events[:] = []
|
|
216
|
+
self.commands.clear_received_reports()
|
|
217
|
+
logging.debug('bbox clear events')
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
pow2 = [2**i for i in range(8)]
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _list2bits(arg):
|
|
224
|
+
# return a numpy.ubyte with bits set based on integers 0..7 in arg
|
|
225
|
+
if type(arg) == int and 0 <= arg < 8:
|
|
226
|
+
return ubyte(pow2[arg])
|
|
227
|
+
elif hasattr(arg, '__iter__'):
|
|
228
|
+
return ubyte(sum([pow2[btn] for btn in arg]))
|
|
229
|
+
else: # None
|
|
230
|
+
return ubyte(0)
|
|
231
|
+
|
|
232
|
+
=======
|
|
233
|
+
>>>>>>> Stashed changes
|
|
234
|
+
|
|
235
|
+
raise DeprecationWarning("The ioLab button box is no longer being sold and the library is no"
|
|
236
|
+
"longer supported. This library has been removed from PsychoPy as of"
|
|
237
|
+
"version 2022.1. We would recommend you use an alternative button box"
|
|
238
|
+
"such as the LabHackers MilliKey <https://www.labhackers.com/millikey.html>")
|
psychopy/hardware/manager.py
CHANGED
psychopy/hardware/photodiode.py
CHANGED
|
@@ -155,7 +155,7 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
|
|
|
155
155
|
|
|
156
156
|
return channels
|
|
157
157
|
|
|
158
|
-
def findPhotodiode(self, win, channel=None):
|
|
158
|
+
def findPhotodiode(self, win, channel=None, retryLimit=5):
|
|
159
159
|
"""
|
|
160
160
|
Draws rectangles on the screen and records photodiode responses to recursively find the location of the diode.
|
|
161
161
|
|
|
@@ -271,32 +271,46 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
|
|
|
271
271
|
# if none of these have returned, rect is too small to cover the whole photodiode, so return
|
|
272
272
|
return responsive
|
|
273
273
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
# if cancelled, warn and continue
|
|
281
|
-
if responsive is None:
|
|
282
|
-
logging.warn(
|
|
283
|
-
"`findPhotodiode` procedure cancelled by user."
|
|
284
|
-
)
|
|
285
|
-
return (
|
|
286
|
-
layout.Position(self.pos, units="norm", win=win),
|
|
287
|
-
layout.Position(self.size, units="norm", win=win),
|
|
288
|
-
)
|
|
289
|
-
# if we didn't get any responses at all, prompt to try again
|
|
290
|
-
if not responsive:
|
|
274
|
+
def handleNonResponse(label, rect, timeout=5):
|
|
275
|
+
# skip if retry limit hit
|
|
276
|
+
if retryLimit <= 0:
|
|
277
|
+
return None
|
|
278
|
+
# start a countdown
|
|
279
|
+
timer = core.CountdownTimer(start=timeout)
|
|
291
280
|
# set label text to alert user
|
|
292
|
-
|
|
281
|
+
msg = (
|
|
293
282
|
"Received no responses from photodiode during `findPhotodiode`. Photodiode may not "
|
|
294
283
|
"be connected or may be configured incorrectly.\n"
|
|
295
284
|
"\n"
|
|
296
|
-
"To
|
|
297
|
-
"
|
|
298
|
-
|
|
299
|
-
|
|
285
|
+
"To manually specify the photodiode's position, press ENTER. To quit, press "
|
|
286
|
+
"ESCAPE. Otherwise, will retry in {:.0f}s\n"
|
|
287
|
+
)
|
|
288
|
+
label.foreColor = "red"
|
|
289
|
+
# start a frame loop until they press enter
|
|
290
|
+
keys = []
|
|
291
|
+
while timer.getTime() > 0 and not keys:
|
|
292
|
+
# get keys
|
|
293
|
+
keys = kb.getKeys()
|
|
294
|
+
# skip if escape pressed
|
|
295
|
+
if "escape" in keys:
|
|
296
|
+
return None
|
|
297
|
+
# specify manually if return pressed
|
|
298
|
+
if "return" in keys:
|
|
299
|
+
return specifyManually(label=label, rect=rect)
|
|
300
|
+
# format label
|
|
301
|
+
label.text = msg.format(timer.getTime())
|
|
302
|
+
# show label and square
|
|
303
|
+
label.draw()
|
|
304
|
+
# flip
|
|
305
|
+
win.flip()
|
|
306
|
+
# if we timed out, retry whole find procedure
|
|
307
|
+
return self.findPhotodiode(win, channel=channel, retryLimit=retryLimit-1)
|
|
308
|
+
|
|
309
|
+
def specifyManually(label, rect):
|
|
310
|
+
# set label text to alert user
|
|
311
|
+
label.text = (
|
|
312
|
+
"Use the arrow keys to move the photodiode patch and use the plus/minus keys to "
|
|
313
|
+
"resize it. Press ENTER when finished, or press ESCAPE to quit.\n"
|
|
300
314
|
)
|
|
301
315
|
label.foreColor = "red"
|
|
302
316
|
# revert to defaults
|
|
@@ -306,12 +320,18 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
|
|
|
306
320
|
# start a frame loop until they press enter
|
|
307
321
|
keys = []
|
|
308
322
|
res = 0.05
|
|
309
|
-
while "return" not in keys:
|
|
323
|
+
while "return" not in keys and "escape" not in keys:
|
|
310
324
|
# get keys
|
|
311
325
|
keys = kb.getKeys()
|
|
312
326
|
# skip if escape pressed
|
|
313
327
|
if "escape" in keys:
|
|
314
328
|
return None
|
|
329
|
+
# finish if return pressed
|
|
330
|
+
if "return" in keys:
|
|
331
|
+
return (
|
|
332
|
+
layout.Position(self.pos, units="norm", win=win),
|
|
333
|
+
layout.Position(self.size, units="norm", win=win),
|
|
334
|
+
)
|
|
315
335
|
# move rect according to arrow keys
|
|
316
336
|
pos = list(rect.pos)
|
|
317
337
|
if "left" in keys:
|
|
@@ -335,13 +355,25 @@ class BasePhotodiodeGroup(base.BaseResponseDevice):
|
|
|
335
355
|
rect.draw()
|
|
336
356
|
# flip
|
|
337
357
|
win.flip()
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
358
|
+
|
|
359
|
+
# reset state
|
|
360
|
+
self.state = [None] * self.channels
|
|
361
|
+
self.dispatchMessages()
|
|
362
|
+
self.clearResponses()
|
|
363
|
+
# recursively shrink rect around the photodiode
|
|
364
|
+
responsive = scanQuadrants()
|
|
365
|
+
# if cancelled, warn and continue
|
|
366
|
+
if responsive is None:
|
|
367
|
+
logging.warn(
|
|
368
|
+
"`findPhotodiode` procedure cancelled by user."
|
|
369
|
+
)
|
|
341
370
|
return (
|
|
342
371
|
layout.Position(self.pos, units="norm", win=win),
|
|
343
372
|
layout.Position(self.size, units="norm", win=win),
|
|
344
373
|
)
|
|
374
|
+
# if we didn't get any responses at all, prompt to try again
|
|
375
|
+
if not responsive:
|
|
376
|
+
handleNonResponse(label=label, rect=rect)
|
|
345
377
|
# clear all the events created by this process
|
|
346
378
|
self.state = [None] * self.channels
|
|
347
379
|
self.dispatchMessages()
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
# Part of the PsychoPy library
|
|
5
|
+
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2022 Open Science Tools Ltd.
|
|
6
|
+
# Distributed under the terms of the GNU General Public License (GPL).
|
|
7
|
+
|
|
8
|
+
"""To connect to serial ports, e.g. to send/receive trigger pulses
|
|
9
|
+
|
|
10
|
+
This is really just a subclass of the Serial class from the pyserial lib, with
|
|
11
|
+
added functions for the purpose of detecting triggers.
|
|
12
|
+
|
|
13
|
+
Also note that to interact with serial port *devices* with APIs such as
|
|
14
|
+
photometers etc then you might be better using the psychopy.hardware.SerialDevice
|
|
15
|
+
base class.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import time
|
|
19
|
+
import serial
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
Note that py serial.Serial has announced deprecating camelCase for
|
|
23
|
+
snake_case as of version 3.0 but not clear when this will actually
|
|
24
|
+
be removed. We're currently sticking with camelCase since that meets
|
|
25
|
+
our own style guide.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class SerialPort(serial.Serial):
|
|
30
|
+
"""
|
|
31
|
+
"""
|
|
32
|
+
def waitTriggers(self, triggers=None, maxWait=None):
|
|
33
|
+
"""Waits for one of the trigger characters to be detected
|
|
34
|
+
|
|
35
|
+
If none of the characters are detected within the maxWait
|
|
36
|
+
then None is returned. Otherwise the value of the detected
|
|
37
|
+
trigger is returned.
|
|
38
|
+
|
|
39
|
+
Params
|
|
40
|
+
------
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
if type(triggers) in [bytes, str]:
|
|
44
|
+
triggers = {triggers}
|
|
45
|
+
t0 = time.time()
|
|
46
|
+
# can't just use serial port timeout because check for char
|
|
47
|
+
while maxWait is None or (time.time()-t0 < maxWait):
|
|
48
|
+
chars = self.read(self.inWaiting())
|
|
49
|
+
for thisTrigger in triggers:
|
|
50
|
+
if thisTrigger in chars:
|
|
51
|
+
return thisTrigger
|
psychopy/hardware/speaker.py
CHANGED
|
@@ -8,7 +8,7 @@ class SpeakerDevice(BaseDevice):
|
|
|
8
8
|
profiles = self.getAvailableDevices()
|
|
9
9
|
|
|
10
10
|
# if index is default (-1), setup a default device index
|
|
11
|
-
if not isinstance(index, (int, float))
|
|
11
|
+
if not isinstance(index, (int, float)):
|
|
12
12
|
index = profiles[0]['index'] # initialize as the first device
|
|
13
13
|
|
|
14
14
|
# check if a default device is already set and update index
|
|
@@ -23,8 +23,8 @@ class SpeakerDevice(BaseDevice):
|
|
|
23
23
|
if profile['deviceName'] == defaultDevice:
|
|
24
24
|
index = profile['index']
|
|
25
25
|
|
|
26
|
-
available_index = [profile['index'] for profile in profiles]
|
|
27
|
-
if index
|
|
26
|
+
available_index = [profile['index'] for profile in profiles] + [-1]
|
|
27
|
+
if index not in available_index:
|
|
28
28
|
logging.error("No speaker device found with index %d" % index)
|
|
29
29
|
|
|
30
30
|
# store index
|
|
@@ -86,4 +86,4 @@ class SpeakerDevice(BaseDevice):
|
|
|
86
86
|
}
|
|
87
87
|
devices.append(device)
|
|
88
88
|
|
|
89
|
-
return devices
|
|
89
|
+
return devices
|