psychopy 2025.1.1__py3-none-any.whl → 2025.2.1__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/VERSION +1 -1
- psychopy/alerts/alertsCatalogue/4810.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertCategories.yaml +4 -0
- psychopy/alerts/alertsCatalogue/alertmsg.py +15 -1
- psychopy/alerts/alertsCatalogue/generateAlertmsg.py +2 -2
- psychopy/app/Resources/classic/add_many.png +0 -0
- psychopy/app/Resources/classic/add_many@2x.png +0 -0
- psychopy/app/Resources/classic/devices.png +0 -0
- psychopy/app/Resources/classic/devices@2x.png +0 -0
- psychopy/app/Resources/classic/photometer.png +0 -0
- psychopy/app/Resources/classic/photometer@2x.png +0 -0
- psychopy/app/Resources/dark/add_many.png +0 -0
- psychopy/app/Resources/dark/add_many@2x.png +0 -0
- psychopy/app/Resources/dark/devices.png +0 -0
- psychopy/app/Resources/dark/devices@2x.png +0 -0
- psychopy/app/Resources/dark/photometer.png +0 -0
- psychopy/app/Resources/dark/photometer@2x.png +0 -0
- psychopy/app/Resources/light/add_many.png +0 -0
- psychopy/app/Resources/light/add_many@2x.png +0 -0
- psychopy/app/Resources/light/devices.png +0 -0
- psychopy/app/Resources/light/devices@2x.png +0 -0
- psychopy/app/Resources/light/photometer.png +0 -0
- psychopy/app/Resources/light/photometer@2x.png +0 -0
- psychopy/app/_psychopyApp.py +35 -13
- psychopy/app/builder/builder.py +88 -35
- psychopy/app/builder/dialogs/__init__.py +69 -220
- psychopy/app/builder/dialogs/dlgsCode.py +29 -8
- psychopy/app/builder/dialogs/paramCtrls.py +1468 -904
- psychopy/app/builder/validators.py +25 -17
- psychopy/app/coder/coder.py +12 -1
- psychopy/app/coder/repl.py +5 -2
- psychopy/app/colorpicker/__init__.py +1 -1
- psychopy/app/deviceManager/__init__.py +1 -0
- psychopy/app/deviceManager/addDialog.py +218 -0
- psychopy/app/deviceManager/dialog.py +185 -0
- psychopy/app/deviceManager/panel.py +191 -0
- psychopy/app/deviceManager/utils.py +60 -0
- psychopy/app/idle.py +7 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +12695 -10592
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +11221 -9712
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.po +10195 -18
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +11917 -9101
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +11924 -9103
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +11917 -9101
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +11084 -9569
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +11590 -5806
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +11091 -9577
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +11072 -9549
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +11071 -9559
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +11072 -9560
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1485 -1137
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +11463 -8757
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +11288 -9434
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.po +10200 -25
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.po +10199 -24
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +11441 -8747
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +11069 -9545
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +12085 -8268
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +11929 -8022
- psychopy/app/plugin_manager/dialog.py +12 -3
- psychopy/app/plugin_manager/packageIndex.py +303 -0
- psychopy/app/plugin_manager/packages.py +203 -63
- psychopy/app/plugin_manager/plugins.py +120 -240
- psychopy/app/preferencesDlg.py +6 -1
- psychopy/app/psychopyApp.py +16 -4
- psychopy/app/runner/runner.py +10 -2
- psychopy/app/runner/scriptProcess.py +8 -3
- psychopy/app/stdout/stdOutRich.py +11 -4
- psychopy/app/themes/icons.py +3 -0
- psychopy/app/utils.py +61 -0
- psychopy/data/experiment.py +133 -23
- psychopy/data/routine.py +12 -0
- psychopy/data/staircase.py +42 -20
- psychopy/data/trial.py +20 -12
- psychopy/data/utils.py +42 -2
- psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +22 -5
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
- psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +2 -12
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +3 -8
- psychopy/demos/builder/Feature Demos/movies/movie.psyexp +220 -0
- psychopy/demos/builder/Feature Demos/movies/readme.md +3 -0
- psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +1 -2
- psychopy/demos/builder/Hardware/camera/camera.psyexp +3 -16
- psychopy/demos/builder/Hardware/microphone/microphone.psyexp +3 -16
- psychopy/demos/coder/hardware/hdf5_extract.py +133 -0
- psychopy/event.py +20 -15
- psychopy/experiment/_experiment.py +86 -10
- psychopy/experiment/components/__init__.py +3 -10
- psychopy/experiment/components/_base.py +9 -20
- psychopy/experiment/components/button/__init__.py +1 -1
- psychopy/experiment/components/buttonBox/__init__.py +50 -54
- psychopy/experiment/components/camera/__init__.py +137 -359
- psychopy/experiment/components/keyboard/__init__.py +17 -24
- psychopy/experiment/components/microphone/__init__.py +61 -110
- psychopy/experiment/components/movie/__init__.py +2 -3
- psychopy/experiment/components/serialOut/__init__.py +192 -93
- psychopy/experiment/components/settings/__init__.py +45 -27
- psychopy/experiment/components/sound/__init__.py +82 -73
- psychopy/experiment/components/soundsensor/__init__.py +43 -80
- psychopy/experiment/devices.py +303 -0
- psychopy/experiment/exports.py +20 -18
- psychopy/experiment/flow.py +7 -0
- psychopy/experiment/loops.py +47 -29
- psychopy/experiment/monitor.py +74 -0
- psychopy/experiment/params.py +48 -10
- psychopy/experiment/plugins.py +28 -108
- psychopy/experiment/py2js_transpiler.py +1 -1
- psychopy/experiment/routines/__init__.py +1 -1
- psychopy/experiment/routines/_base.py +59 -24
- psychopy/experiment/routines/audioValidator/__init__.py +19 -155
- psychopy/experiment/routines/visualValidator/__init__.py +25 -25
- psychopy/hardware/__init__.py +20 -57
- psychopy/hardware/button.py +15 -2
- psychopy/hardware/camera/__init__.py +2237 -1394
- psychopy/hardware/joystick/__init__.py +1 -1
- psychopy/hardware/keyboard.py +5 -8
- psychopy/hardware/listener.py +4 -1
- psychopy/hardware/manager.py +75 -35
- psychopy/hardware/microphone.py +52 -6
- psychopy/hardware/monitor.py +144 -0
- psychopy/hardware/photometer/__init__.py +156 -117
- psychopy/hardware/serialdevice.py +16 -2
- psychopy/hardware/soundsensor.py +4 -1
- psychopy/iohub/devices/deviceConfigValidation.py +2 -1
- psychopy/iohub/devices/keyboard/darwin.py +8 -5
- psychopy/iohub/util/__init__.py +7 -8
- psychopy/localization/generateTranslationTemplate.py +208 -116
- psychopy/localization/messages.pot +4305 -3502
- psychopy/monitors/MonitorCenter.py +174 -74
- psychopy/plugins/__init__.py +6 -4
- psychopy/preferences/devices.py +80 -0
- psychopy/preferences/generateHints.py +2 -1
- psychopy/preferences/preferences.py +35 -11
- psychopy/scripts/psychopy-pkgutil.py +969 -0
- psychopy/scripts/psyexpCompile.py +1 -1
- psychopy/session.py +34 -38
- psychopy/sound/__init__.py +6 -260
- psychopy/sound/audioclip.py +164 -0
- psychopy/sound/backend_ptb.py +8 -0
- psychopy/sound/backend_pygame.py +10 -0
- psychopy/sound/backend_pysound.py +9 -0
- psychopy/sound/backends/__init__.py +0 -0
- psychopy/sound/microphone.py +3 -0
- psychopy/sound/sound.py +58 -0
- psychopy/tests/data/correctScript/python/correctNoiseStimComponent.py +1 -1
- psychopy/tests/data/duplicateHeaders.csv +2 -0
- psychopy/tests/test_app/test_builder/test_BuilderFrame.py +22 -7
- psychopy/tests/test_app/test_builder/test_CompileFromBuilder.py +0 -2
- psychopy/tests/test_data/test_utils.py +5 -1
- psychopy/tests/test_experiment/test_components/test_ButtonBoxComponent.py +22 -2
- psychopy/tests/test_hardware/test_ports.py +0 -12
- psychopy/tests/test_tools/test_stringtools.py +1 -1
- psychopy/tools/attributetools.py +12 -5
- psychopy/tools/fontmanager.py +17 -14
- psychopy/tools/movietools.py +43 -2
- psychopy/tools/stringtools.py +33 -8
- psychopy/tools/versionchooser.py +1 -1
- psychopy/validation/audio.py +5 -1
- psychopy/validation/visual.py +5 -1
- psychopy/visual/basevisual.py +8 -7
- psychopy/visual/circle.py +2 -2
- psychopy/visual/image.py +29 -109
- psychopy/visual/movies/__init__.py +1800 -313
- psychopy/visual/polygon.py +4 -0
- psychopy/visual/shape.py +2 -2
- psychopy/visual/window.py +34 -11
- psychopy/voicekey/__init__.py +41 -669
- psychopy/voicekey/labjack_vks.py +7 -48
- psychopy/voicekey/parallel_vks.py +7 -42
- psychopy/voicekey/vk_tools.py +114 -263
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/METADATA +17 -11
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/RECORD +216 -184
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/WHEEL +1 -1
- psychopy/visual/movies/players/__init__.py +0 -62
- psychopy/visual/movies/players/ffpyplayer_player.py +0 -1401
- psychopy/voicekey/demo_vks.py +0 -12
- psychopy/voicekey/signal.py +0 -42
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/entry_points.txt +0 -0
- {psychopy-2025.1.1.dist-info → psychopy-2025.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -18,151 +18,190 @@ __all__ = [
|
|
|
18
18
|
'getAllPhotometerClasses'
|
|
19
19
|
]
|
|
20
20
|
|
|
21
|
+
from psychopy.hardware.base import BaseResponseDevice, BaseResponse
|
|
22
|
+
from psychopy import layout, logging
|
|
23
|
+
|
|
21
24
|
from psychopy.plugins import PluginStub
|
|
22
25
|
|
|
23
|
-
# Special handling for legacy classes which have been offloaded to optional
|
|
24
|
-
# packages. This will change to allow more flexibility in the future to avoid
|
|
25
|
-
# updating this package for additions to these sub-packages. We'll need a
|
|
26
|
-
# photometer type to do that, but for now we're doing it like this.
|
|
27
|
-
from psychopy.hardware.crs.colorcal import ColorCAL
|
|
28
|
-
from psychopy.hardware.crs.optical import OptiCAL
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
class PhotometerResponse(BaseResponse):
|
|
28
|
+
"""
|
|
29
|
+
Response from a photometer device. Value can be a single integer, could represent overall
|
|
30
|
+
luminance or the value of a single gun.
|
|
31
|
+
"""
|
|
32
|
+
pass
|
|
32
33
|
|
|
33
|
-
# Konica Minolta light-measuring devices
|
|
34
|
-
from psychopy.hardware.minolta import LS100, CS100A
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
class BasePhotometerDevice(BaseResponseDevice):
|
|
36
|
+
responseClass = PhotometerResponse
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
def getLum(self):
|
|
39
|
+
"""
|
|
40
|
+
Get luminance according to pixel values.
|
|
41
|
+
"""
|
|
42
|
+
# dispatch messages and return the most recent
|
|
43
|
+
self.dispatchMessages()
|
|
44
|
+
if self.responses:
|
|
45
|
+
resp = self.responses[-1]
|
|
46
|
+
return resp.value
|
|
47
|
+
else:
|
|
48
|
+
# if no messages, assume no luminance
|
|
49
|
+
return 0
|
|
41
50
|
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
"""
|
|
52
|
+
class ScreenBufferPhotometerDevice(BasePhotometerDevice):
|
|
53
|
+
"""
|
|
54
|
+
Samples pixel colors from the screen buffer to emulate a photometer. Useful only for teaching,
|
|
55
|
+
as the output will always behave as if the screen is perfectly calibrated, as there's no
|
|
56
|
+
physical measurement involved.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
win : psychopy.visual.Window
|
|
61
|
+
Window to pull pixel values from
|
|
62
|
+
pos : tuple, list
|
|
63
|
+
Position of the patch of pixels to pretend there is a photometer looking at
|
|
64
|
+
size : tuple, list
|
|
65
|
+
Size of the patch of pixels to pretend there is a photometer looking at
|
|
66
|
+
units : str
|
|
67
|
+
"Spatial units in which to interpret size and position"
|
|
68
|
+
"""
|
|
69
|
+
def __init__(self, win, pos=None, size=None, units=None):
|
|
70
|
+
# initialize
|
|
71
|
+
BaseResponseDevice.__init__(self)
|
|
72
|
+
# store win
|
|
73
|
+
self.win = win
|
|
74
|
+
# default rect
|
|
75
|
+
self.rect = None
|
|
76
|
+
# make clock
|
|
77
|
+
from psychopy.core import Clock
|
|
78
|
+
self.clock = Clock()
|
|
79
|
+
# store position params
|
|
80
|
+
self.units = units
|
|
81
|
+
self.pos = pos
|
|
82
|
+
self.size = size
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def pos(self):
|
|
86
|
+
return getattr(self._pos, self.units)
|
|
87
|
+
|
|
88
|
+
@pos.setter
|
|
89
|
+
def pos(self, value):
|
|
90
|
+
self._pos = layout.Position(value, units=self.units, win=self.win)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def size(self):
|
|
94
|
+
return getattr(self._size, self.units)
|
|
95
|
+
|
|
96
|
+
@size.setter
|
|
97
|
+
def size(self, value):
|
|
98
|
+
self._size = layout.Size(value, units=self.units, win=self.win)
|
|
99
|
+
|
|
100
|
+
def dispatchMessages(self):
|
|
101
|
+
"""
|
|
102
|
+
When called, dispatch a single reading.
|
|
103
|
+
"""
|
|
104
|
+
# get rect
|
|
105
|
+
left, bottom = self._pos.pix + self.win.size / 2
|
|
106
|
+
w, h = self._size.pix
|
|
107
|
+
left = int(left - w / 2)
|
|
108
|
+
bottom = int(bottom - h / 2)
|
|
109
|
+
w = int(w)
|
|
110
|
+
h = int(h)
|
|
111
|
+
# read front buffer luminances for specified area
|
|
112
|
+
pixels = self.win._getPixels(
|
|
113
|
+
buffer="front",
|
|
114
|
+
rect=(left, bottom, w, h),
|
|
115
|
+
makeLum=True
|
|
116
|
+
)
|
|
117
|
+
# dispatch a message
|
|
118
|
+
self.receiveMessage(
|
|
119
|
+
self.parseMessage(pixels.mean() / 255)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
def parseMessage(self, message):
|
|
123
|
+
return PhotometerResponse(
|
|
124
|
+
t=self.clock.getTime(),
|
|
125
|
+
value=message,
|
|
126
|
+
device=self
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def isSameDevice(self, other):
|
|
130
|
+
return isinstance(other, ScreenBufferPhotometerDevice)
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def getAvailableDevices():
|
|
134
|
+
# there's only ever one
|
|
135
|
+
return [{
|
|
136
|
+
'deviceName': "Photometer Emulator",
|
|
137
|
+
'deviceClass': "psychopy.hardware.photometer.ScreenBufferPhotometerDevice",
|
|
138
|
+
'win': "session.win",
|
|
139
|
+
}]
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# --- legacy methods ---
|
|
45
143
|
|
|
46
|
-
Once a photometer class is registered, it will be discoverable when
|
|
47
|
-
:func:`getAllPhotometers()` is called. This function is also used by the
|
|
48
|
-
plugin interface to add new interfaces at runtime.
|
|
49
144
|
|
|
50
|
-
|
|
51
|
-
|
|
145
|
+
def addPhotometer(cls):
|
|
146
|
+
"""
|
|
147
|
+
DEPRECATED: Photometer classes are added on import, so this function is no longer needed.
|
|
52
148
|
|
|
53
149
|
Parameters
|
|
54
150
|
----------
|
|
55
151
|
cls : Any
|
|
56
152
|
Class specifying a photometer interface.
|
|
57
|
-
|
|
58
153
|
"""
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
raise AttributeError(
|
|
64
|
-
"Photometer interface class does not define member `driverFor` and "
|
|
65
|
-
"cannot be added.")
|
|
66
|
-
|
|
67
|
-
# add interface references to dictionary
|
|
68
|
-
if isinstance(cls.driverFor, (list, tuple)):
|
|
69
|
-
# multiple devices sharing the same interface
|
|
70
|
-
for devModel in cls.driverFor:
|
|
71
|
-
if not isinstance(devModel, str): # items must be all strings
|
|
72
|
-
raise TypeError(
|
|
73
|
-
"Invalid item type for array `driverFor`. Items must all "
|
|
74
|
-
"have type `str`.")
|
|
75
|
-
photometerInterfaces[devModel] = cls
|
|
76
|
-
elif isinstance(cls.driverFor, str):
|
|
77
|
-
devModel = cls.driverFor
|
|
78
|
-
photometerInterfaces[devModel] = cls
|
|
79
|
-
else:
|
|
80
|
-
raise TypeError(
|
|
81
|
-
"Invalid type for `driverFor` member specified. Must be either "
|
|
82
|
-
"`str`, `tuple` or `list`.")
|
|
154
|
+
logging.warning(
|
|
155
|
+
"`addPhotometer` is deprecated, photometer classes are added on import so this function "
|
|
156
|
+
"is not needed."
|
|
157
|
+
)
|
|
83
158
|
|
|
84
159
|
|
|
85
160
|
def getAllPhotometers():
|
|
86
|
-
"""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Standalone PsychoPy ships with libraries for all supported photometers.
|
|
161
|
+
"""
|
|
162
|
+
Legacy method to get available photometers. Will return subclasses of BasePhotometerDevice as
|
|
163
|
+
well as legacy handlers for previously supported devices.
|
|
90
164
|
|
|
91
165
|
Returns
|
|
92
166
|
-------
|
|
93
167
|
dict
|
|
94
|
-
|
|
95
|
-
names the interface works with and the values are references to the
|
|
96
|
-
unbound interface class associated with it. Keys can have the same value
|
|
97
|
-
the interface is common to multiple devices.
|
|
98
|
-
|
|
168
|
+
Device classes against the names by which to represent them.
|
|
99
169
|
"""
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
#
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
addPhotometer(photom)
|
|
126
|
-
|
|
127
|
-
# Merge with classes from plugins. Duplicate names will be overwritten by
|
|
128
|
-
# the plugins.
|
|
129
|
-
foundPhotometers.update(photometerInterfaces)
|
|
130
|
-
|
|
131
|
-
return foundPhotometers.copy()
|
|
170
|
+
# get photometer classes the new way: by looking for subclasses of BasePhotometerDevice
|
|
171
|
+
found = BasePhotometerDevice.__subclasses__()
|
|
172
|
+
# import classes which used to be in PsychoPy
|
|
173
|
+
from psychopy.hardware.crs.colorcal import ColorCAL
|
|
174
|
+
from psychopy.hardware.crs.optical import OptiCAL
|
|
175
|
+
from psychopy.hardware.pr import PR655, PR650
|
|
176
|
+
from psychopy.hardware.minolta import LS100, CS100A
|
|
177
|
+
from psychopy.hardware.gammasci import S470
|
|
178
|
+
# include any which aren't PluginStub's
|
|
179
|
+
for cls in (
|
|
180
|
+
ColorCAL,
|
|
181
|
+
OptiCAL,
|
|
182
|
+
PR655,
|
|
183
|
+
PR650,
|
|
184
|
+
LS100,
|
|
185
|
+
CS100A,
|
|
186
|
+
S470
|
|
187
|
+
):
|
|
188
|
+
if not issubclass(cls, PluginStub):
|
|
189
|
+
found.append(cls)
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
cls.__name__: cls
|
|
193
|
+
for cls in found
|
|
194
|
+
}
|
|
132
195
|
|
|
133
196
|
|
|
134
197
|
def getAllPhotometerClasses():
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
:func:`~psychopy.hardware.getAllPhotometers()` function call.
|
|
198
|
+
"""
|
|
199
|
+
Legacy method to get available photometers. Will return subclasses of BasePhotometerDevice as
|
|
200
|
+
well as legacy handlers for previously supported devices.
|
|
139
201
|
|
|
140
202
|
Returns
|
|
141
203
|
-------
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
204
|
+
dict
|
|
205
|
+
Device classes against the names by which to represent them.
|
|
145
206
|
"""
|
|
146
|
-
|
|
147
|
-
photometers = getAllPhotometers()
|
|
148
|
-
|
|
149
|
-
if not photometers: # do nothing if no photometers found
|
|
150
|
-
return []
|
|
151
|
-
|
|
152
|
-
interfaceIDs = [] # a store unique IDs for interfaces
|
|
153
|
-
# Remove items the are duplicated, i.e. multiple IDs that have a common
|
|
154
|
-
# interface.
|
|
155
|
-
knownInterfaces = []
|
|
156
|
-
for cls in photometers.values():
|
|
157
|
-
clsID = id(cls)
|
|
158
|
-
if clsID in interfaceIDs: # already added
|
|
159
|
-
continue
|
|
160
|
-
|
|
161
|
-
interfaceIDs.append(clsID)
|
|
162
|
-
knownInterfaces.append(cls)
|
|
163
|
-
|
|
164
|
-
return knownInterfaces
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if __name__ == "__main__":
|
|
168
|
-
pass
|
|
207
|
+
return getAllPhotometers()
|
|
@@ -293,7 +293,21 @@ class SerialDevice(BaseDevice, AttributeGetSetMixin):
|
|
|
293
293
|
t = time.time() - start
|
|
294
294
|
resp = self.com.read()
|
|
295
295
|
# get remaining chars
|
|
296
|
-
|
|
296
|
+
active = True
|
|
297
|
+
while active and t < timeout:
|
|
298
|
+
# get resp
|
|
299
|
+
thisResp = self.com.read_until(self.eol)
|
|
300
|
+
# concatenate it to what we already have
|
|
301
|
+
resp += thisResp
|
|
302
|
+
# decide whether to continue
|
|
303
|
+
if thisResp.endswith(self.eol) and not multiline:
|
|
304
|
+
# in single line mode, always stop after an eol
|
|
305
|
+
active = False
|
|
306
|
+
else:
|
|
307
|
+
# otherwise, continue so long as we have a response
|
|
308
|
+
active = len(thisResp)
|
|
309
|
+
# wait for more
|
|
310
|
+
self.pause()
|
|
297
311
|
# if we timed out, return None
|
|
298
312
|
if t > timeout:
|
|
299
313
|
return
|
|
@@ -301,7 +315,7 @@ class SerialDevice(BaseDevice, AttributeGetSetMixin):
|
|
|
301
315
|
resp = resp.decode('utf-8')
|
|
302
316
|
# if multiline, split by eol
|
|
303
317
|
if multiline:
|
|
304
|
-
resp = resp.split(
|
|
318
|
+
resp = resp.split(self.eol.decode("utf-8"))
|
|
305
319
|
|
|
306
320
|
return resp
|
|
307
321
|
|
psychopy/hardware/soundsensor.py
CHANGED
|
@@ -346,6 +346,9 @@ class MicrophoneSoundSensor(BaseSoundSensorGroup):
|
|
|
346
346
|
self.getThreshold(channel=channel) * (max(self.dbRange) - min(self.dbRange))
|
|
347
347
|
)
|
|
348
348
|
|
|
349
|
+
def getCurrentVolume(self):
|
|
350
|
+
return self.device.getCurrentVolume()
|
|
351
|
+
|
|
349
352
|
def _setThreshold(self, threshold, channel=None):
|
|
350
353
|
"""
|
|
351
354
|
No additional setup is needed for emulator as thresholding is emulated outside of the
|
|
@@ -367,7 +370,7 @@ class MicrophoneSoundSensor(BaseSoundSensorGroup):
|
|
|
367
370
|
vol = max(vol)
|
|
368
371
|
# transform volume to arbitrary units
|
|
369
372
|
adjVol = int(
|
|
370
|
-
(vol - min(self.dbRange)) / (max(self.dbRange) - min(self.dbRange))
|
|
373
|
+
(vol - min(self.dbRange)) / (max(self.dbRange) - min(self.dbRange))
|
|
371
374
|
)
|
|
372
375
|
# iterate through channels
|
|
373
376
|
for channel in range(self.channels):
|
|
@@ -490,7 +490,8 @@ def validateDeviceConfiguration(
|
|
|
490
490
|
"""Validate the device configuration settings provided.
|
|
491
491
|
"""
|
|
492
492
|
validation_module = importDeviceModule(relative_module_path)
|
|
493
|
-
validation_file_path = getSupportedConfigSettings(
|
|
493
|
+
validation_file_path = getSupportedConfigSettings(
|
|
494
|
+
validation_module, deviceClassName=device_class_name)
|
|
494
495
|
|
|
495
496
|
# use a default config if we can't get the YAML file
|
|
496
497
|
if not os.path.exists(validation_file_path):
|
|
@@ -11,6 +11,7 @@ from .. import Computer, Device
|
|
|
11
11
|
|
|
12
12
|
#>>>>>>>>>>>>>>>>>>>>>>>>
|
|
13
13
|
|
|
14
|
+
import sys
|
|
14
15
|
import ctypes
|
|
15
16
|
import ctypes.util
|
|
16
17
|
import CoreFoundation
|
|
@@ -47,13 +48,10 @@ psychopy_numlock_key_mappings['.'] = 'num_decimal'
|
|
|
47
48
|
carbon_path = ctypes.util.find_library('Carbon')
|
|
48
49
|
carbon = ctypes.cdll.LoadLibrary(carbon_path)
|
|
49
50
|
|
|
50
|
-
_objc = ctypes.PyDLL(objc._objc.__file__)
|
|
51
|
-
_objc.PyObjCObject_New.restype = ctypes.py_object
|
|
52
|
-
_objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
|
|
53
|
-
|
|
54
51
|
|
|
55
52
|
def objcify(ptr):
|
|
56
|
-
return
|
|
53
|
+
return objc.objc_object(c_void_p=ptr)
|
|
54
|
+
|
|
57
55
|
|
|
58
56
|
kTISPropertyUnicodeKeyLayoutData_p = ctypes.c_void_p.in_dll(
|
|
59
57
|
carbon, 'kTISPropertyUnicodeKeyLayoutData')
|
|
@@ -123,6 +121,11 @@ modifier_name_mappings = dict(
|
|
|
123
121
|
|
|
124
122
|
|
|
125
123
|
class Keyboard(ioHubKeyboardDevice):
|
|
124
|
+
"""Keyboard device class for iohub on Mac OS X using Quartz.
|
|
125
|
+
|
|
126
|
+
This class uses the Quartz API to monitor keyboard events on Mac OS X.
|
|
127
|
+
|
|
128
|
+
"""
|
|
126
129
|
_last_mod_names = []
|
|
127
130
|
_OS_MODIFIERS = ([(0x00001, 'lctrl'), (0x02000, 'rctrl'),
|
|
128
131
|
(0x00002, 'lshift'), (0x00004, 'rshift'),
|
psychopy/iohub/util/__init__.py
CHANGED
|
@@ -168,14 +168,13 @@ def getSupportedConfigSettings(moduleName, deviceClassName=None):
|
|
|
168
168
|
fileName = 'supported_config_settings_{0}.yaml'.format(
|
|
169
169
|
deviceClassName.lower())
|
|
170
170
|
yamlFile = yamlRoot / pathlib.Path(moduleName.__file__).parent / fileName
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
"
|
|
174
|
-
|
|
175
|
-
logging.debug(
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return str(yamlFile)
|
|
171
|
+
if yamlFile.exists():
|
|
172
|
+
logging.debug(
|
|
173
|
+
"Found ioHub device configuration file: {0}".format(yamlFile))
|
|
174
|
+
return str(yamlFile)
|
|
175
|
+
logging.debug(("No configuration matching device class name '{0}' found in "
|
|
176
|
+
"module dir {1}. Using default config file instead.").format(
|
|
177
|
+
deviceClassName, yamlRoot))
|
|
179
178
|
|
|
180
179
|
# file name for yaml file name convention for single file
|
|
181
180
|
yamlFile = yamlRoot / pathlib.Path('supported_config_settings.yaml')
|