psychopy 2024.1.4__py3-none-any.whl → 2024.2.0__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.

Files changed (325) hide show
  1. psychopy/.DS_Store +0 -0
  2. psychopy/CHANGELOG.txt +206 -0
  3. psychopy/GIT_SHA +1 -0
  4. psychopy/VERSION +1 -0
  5. psychopy/__init__.py +77 -15
  6. psychopy/app/Resources/classic/plugin16.png +0 -0
  7. psychopy/app/Resources/classic/plugin16@2x.png +0 -0
  8. psychopy/app/Resources/dark/plugin16.png +0 -0
  9. psychopy/app/Resources/dark/plugin16@2x.png +0 -0
  10. psychopy/app/Resources/light/plugin16.png +0 -0
  11. psychopy/app/Resources/light/plugin16@2x.png +0 -0
  12. psychopy/app/__init__.py +76 -2
  13. psychopy/app/_psychopyApp.py +126 -101
  14. psychopy/app/builder/builder.py +14 -10
  15. psychopy/app/builder/dialogs/__init__.py +8 -8
  16. psychopy/app/builder/dialogs/dlgsConditions.py +12 -13
  17. psychopy/app/builder/dialogs/paramCtrls.py +24 -57
  18. psychopy/app/builder/validators.py +2 -2
  19. psychopy/app/coder/codeEditorBase.py +8 -8
  20. psychopy/app/coder/coder.py +4 -4
  21. psychopy/app/connections/sendusage.py +2 -2
  22. psychopy/app/connections/updates.py +9 -9
  23. psychopy/app/dialogs.py +34 -2
  24. psychopy/app/idle.py +31 -0
  25. psychopy/app/jobs.py +21 -3
  26. psychopy/app/linuxconfig/__init__.py +9 -0
  27. psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
  28. psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4602 -2540
  29. psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
  30. psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +56 -54
  31. psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +53 -43
  32. psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
  33. psychopy/app/locale/es_US/LC_MESSAGE/messages.po +56 -54
  34. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
  35. psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +1011 -942
  36. psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +9415 -5
  37. psychopy/app/pavlovia_ui/_base.py +33 -3
  38. psychopy/app/pavlovia_ui/search.py +0 -1
  39. psychopy/app/plugin_manager/dialog.py +104 -51
  40. psychopy/app/plugin_manager/packages.py +5 -0
  41. psychopy/app/plugin_manager/plugins.py +145 -67
  42. psychopy/app/preferencesDlg.py +8 -8
  43. psychopy/app/psychopyApp.py +11 -5
  44. psychopy/app/ribbon.py +124 -14
  45. psychopy/app/runner/runner.py +6 -1
  46. psychopy/app/stdout/stdOutRich.py +27 -11
  47. psychopy/app/themes/icons.py +52 -2
  48. psychopy/assets/__init__.py +0 -0
  49. psychopy/assets/click.png +0 -0
  50. psychopy/assets/clicknext.png +0 -0
  51. psychopy/assets/next.png +0 -0
  52. psychopy/assets/psychopy.ico +0 -0
  53. psychopy/assets/psychopy.png +0 -0
  54. psychopy/assets/templates/__init__.py +0 -0
  55. psychopy/assets/touch.png +0 -0
  56. psychopy/assets/touchnext.png +0 -0
  57. psychopy/assets/window.ico +0 -0
  58. psychopy/changes/2023.1.0.md +9 -0
  59. psychopy/changes/2024.1.0.md +16 -0
  60. psychopy/changes/__init__.py +0 -0
  61. psychopy/clock.py +2 -2
  62. psychopy/colors.py +2 -1
  63. psychopy/compatibility.py +53 -1
  64. psychopy/contrib/.DS_Store +0 -0
  65. psychopy/contrib/configobj/__init__.py +10 -8
  66. psychopy/data/__init__.py +3 -2
  67. psychopy/data/base.py +5 -5
  68. psychopy/data/experiment.py +130 -4
  69. psychopy/data/routine.py +56 -0
  70. psychopy/data/staircase.py +2 -2
  71. psychopy/data/trial.py +559 -97
  72. psychopy/data/utils.py +56 -21
  73. psychopy/demos/.DS_Store +0 -0
  74. psychopy/demos/builder/.DS_Store +0 -0
  75. psychopy/demos/builder/Design Templates/.DS_Store +0 -0
  76. psychopy/demos/builder/Experiments/.DS_Store +0 -0
  77. psychopy/demos/builder/Feature Demos/.DS_Store +0 -0
  78. psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +375 -0
  79. psychopy/demos/builder/Feature Demos/buttonBox/readme.md +5 -0
  80. psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +433 -0
  81. psychopy/demos/builder/Feature Demos/pilotMode/readme.md +7 -0
  82. psychopy/demos/builder/Hardware/.DS_Store +0 -0
  83. psychopy/demos/builder/Helper Tools/.DS_Store +0 -0
  84. psychopy/demos/coder/.DS_Store +0 -0
  85. psychopy/demos/coder/hardware/testSoundLatency.py +2 -2
  86. psychopy/demos/coder/iohub/.DS_Store +0 -0
  87. psychopy/demos/coder/misc/hdf5_2_csv +33 -0
  88. psychopy/event.py +30 -29
  89. psychopy/experiment/.DS_Store +0 -0
  90. psychopy/experiment/_experiment.py +6 -6
  91. psychopy/experiment/components/.DS_Store +0 -0
  92. psychopy/experiment/components/__init__.py +6 -3
  93. psychopy/experiment/components/_base.py +286 -131
  94. psychopy/experiment/components/aperture/.DS_Store +0 -0
  95. psychopy/experiment/components/brush/.DS_Store +0 -0
  96. psychopy/experiment/components/button/.DS_Store +0 -0
  97. psychopy/experiment/components/button/__init__.py +5 -1
  98. psychopy/experiment/components/buttonBox/.DS_Store +0 -0
  99. psychopy/experiment/components/camera/.DS_Store +0 -0
  100. psychopy/experiment/components/code/.DS_Store +0 -0
  101. psychopy/experiment/components/dots/.DS_Store +0 -0
  102. psychopy/experiment/components/eyetracker_record/.DS_Store +0 -0
  103. psychopy/experiment/components/eyetracker_record/__init__.py +92 -30
  104. psychopy/experiment/components/form/.DS_Store +0 -0
  105. psychopy/experiment/components/form/__init__.py +6 -2
  106. psychopy/experiment/components/grating/.DS_Store +0 -0
  107. psychopy/experiment/components/grating/__init__.py +14 -3
  108. psychopy/experiment/components/image/.DS_Store +0 -0
  109. psychopy/experiment/components/image/__init__.py +14 -3
  110. psychopy/experiment/components/joyButtons/.DS_Store +0 -0
  111. psychopy/experiment/components/joystick/.DS_Store +0 -0
  112. psychopy/experiment/components/keyboard/.DS_Store +0 -0
  113. psychopy/experiment/components/keyboard/__init__.py +22 -10
  114. psychopy/experiment/components/microphone/.DS_Store +0 -0
  115. psychopy/experiment/components/microphone/__init__.py +59 -39
  116. psychopy/experiment/components/mouse/.DS_Store +0 -0
  117. psychopy/experiment/components/mouse/__init__.py +44 -29
  118. psychopy/experiment/components/movie/.DS_Store +0 -0
  119. psychopy/experiment/components/movie/__init__.py +1 -1
  120. psychopy/experiment/components/panorama/.DS_Store +0 -0
  121. psychopy/experiment/components/parallelOut/.DS_Store +0 -0
  122. psychopy/experiment/components/patch/.DS_Store +0 -0
  123. psychopy/experiment/components/polygon/.DS_Store +0 -0
  124. psychopy/experiment/components/polygon/__init__.py +26 -6
  125. psychopy/experiment/components/progress/.DS_Store +0 -0
  126. psychopy/experiment/components/ratingScale/.DS_Store +0 -0
  127. psychopy/experiment/components/resourceManager/.DS_Store +0 -0
  128. psychopy/experiment/components/roi/.DS_Store +0 -0
  129. psychopy/experiment/components/roi/__init__.py +5 -0
  130. psychopy/experiment/components/routineSettings/.DS_Store +0 -0
  131. psychopy/experiment/components/routineSettings/__init__.py +57 -10
  132. psychopy/experiment/components/serialOut/.DS_Store +0 -0
  133. psychopy/experiment/components/settings/.DS_Store +0 -0
  134. psychopy/experiment/components/settings/__init__.py +117 -42
  135. psychopy/experiment/components/slider/.DS_Store +0 -0
  136. psychopy/experiment/components/sound/.DS_Store +0 -0
  137. psychopy/experiment/components/sound/__init__.py +54 -19
  138. psychopy/experiment/components/static/.DS_Store +0 -0
  139. psychopy/experiment/components/static/__init__.py +1 -1
  140. psychopy/experiment/components/text/.DS_Store +0 -0
  141. psychopy/experiment/components/text/__init__.py +28 -3
  142. psychopy/experiment/components/textbox/.DS_Store +0 -0
  143. psychopy/experiment/components/textbox/__init__.py +12 -2
  144. psychopy/experiment/components/unknown/.DS_Store +0 -0
  145. psychopy/experiment/components/unknown/__init__.py +1 -2
  146. psychopy/experiment/components/unknownPlugin/.DS_Store +0 -0
  147. psychopy/experiment/components/unknownPlugin/__init__.py +2 -2
  148. psychopy/experiment/components/variable/.DS_Store +0 -0
  149. psychopy/experiment/flow.py +11 -4
  150. psychopy/experiment/loops.py +85 -37
  151. psychopy/experiment/params.py +74 -32
  152. psychopy/experiment/py2js_transpiler.py +8 -1
  153. psychopy/experiment/routines/.DS_Store +0 -0
  154. psychopy/experiment/routines/_base.py +102 -22
  155. psychopy/experiment/routines/counterbalance/.DS_Store +0 -0
  156. psychopy/experiment/routines/counterbalance/__init__.py +5 -1
  157. psychopy/experiment/routines/eyetracker_calibrate/.DS_Store +0 -0
  158. psychopy/experiment/routines/eyetracker_validate/.DS_Store +0 -0
  159. psychopy/experiment/routines/pavlovia_survey/.DS_Store +0 -0
  160. psychopy/experiment/routines/photodiodeValidator/.DS_Store +0 -0
  161. psychopy/experiment/routines/photodiodeValidator/__init__.py +6 -5
  162. psychopy/experiment/routines/unknown/.DS_Store +0 -0
  163. psychopy/gui/wxgui.py +4 -4
  164. psychopy/hardware/.DS_Store +0 -0
  165. psychopy/hardware/__init__.py +1 -1
  166. psychopy/hardware/base.py +12 -0
  167. psychopy/hardware/camera/__init__.py +1 -15
  168. psychopy/hardware/cedrus.py +10 -11
  169. psychopy/hardware/crs/colorcal.py +13 -22
  170. psychopy/hardware/crs/optical.py +10 -20
  171. psychopy/hardware/emulator.py +17 -14
  172. psychopy/hardware/eyetracker.py +42 -118
  173. psychopy/hardware/gammasci.py +4 -15
  174. psychopy/hardware/keyboard.py +102 -10
  175. psychopy/hardware/listener.py +3 -0
  176. psychopy/hardware/microphone.py +148 -18
  177. psychopy/hardware/minolta.py +8 -15
  178. psychopy/hardware/photodiode.py +191 -16
  179. psychopy/hardware/photometer/__init__.py +11 -19
  180. psychopy/hardware/pr.py +8 -15
  181. psychopy/hardware/speaker.py +39 -4
  182. psychopy/info.py +0 -71
  183. psychopy/iohub/.DS_Store +0 -0
  184. psychopy/iohub/__init__.py +1 -1
  185. psychopy/iohub/client/__init__.py +30 -20
  186. psychopy/iohub/client/keyboard.py +24 -24
  187. psychopy/iohub/datastore/__init__.py +2 -2
  188. psychopy/iohub/datastore/util.py +2 -2
  189. psychopy/iohub/default_config.yaml +1 -1
  190. psychopy/iohub/devices/.DS_Store +0 -0
  191. psychopy/iohub/devices/__init__.py +112 -25
  192. psychopy/iohub/devices/deviceConfigValidation.py +2 -1
  193. psychopy/iohub/devices/experiment/default_experiment.yaml +12 -1
  194. psychopy/iohub/devices/experiment/supported_config_settings.yaml +5 -1
  195. psychopy/iohub/devices/eyetracker/.DS_Store +0 -0
  196. psychopy/iohub/devices/eyetracker/__init__.py +46 -0
  197. psychopy/iohub/devices/eyetracker/calibration/procedure.py +2 -2
  198. psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +14 -2
  199. psychopy/iohub/devices/eyetracker/hw/mouse/eyetracker.py +3 -4
  200. psychopy/iohub/server.py +2 -2
  201. psychopy/iohub/start_iohub_process.py +3 -0
  202. psychopy/iohub/util/__init__.py +62 -70
  203. psychopy/layout.py +5 -5
  204. psychopy/logging.py +8 -1
  205. psychopy/microphone.py +10 -37
  206. psychopy/platform_specific/__init__.py +0 -2
  207. psychopy/platform_specific/darwin.py +1 -3
  208. psychopy/platform_specific/linux.py +31 -33
  209. psychopy/platform_specific/win32.py +38 -13
  210. psychopy/plugins/__init__.py +148 -116
  211. psychopy/plugins/util.py +39 -0
  212. psychopy/preferences/Darwin.spec +4 -2
  213. psychopy/preferences/FreeBSD.spec +4 -2
  214. psychopy/preferences/Linux.spec +4 -2
  215. psychopy/preferences/Windows.spec +4 -2
  216. psychopy/preferences/baseNoArch.spec +4 -2
  217. psychopy/preferences/preferences.py +47 -24
  218. psychopy/projects/pavlovia.py +47 -4
  219. psychopy/scripts/psyexpCompile.py +0 -4
  220. psychopy/session.py +153 -21
  221. psychopy/sound/__init__.py +31 -21
  222. psychopy/sound/_base.py +20 -3
  223. psychopy/sound/audioclip.py +320 -33
  224. psychopy/sound/backend_ptb.py +47 -58
  225. psychopy/sound/backend_pygame.py +1 -1
  226. psychopy/sound/backend_pysound.py +6 -15
  227. psychopy/sound/transcribe.py +53 -0
  228. psychopy/tests/.DS_Store +0 -0
  229. psychopy/tests/data/.DS_Store +0 -0
  230. psychopy/tests/data/TestUnknownPluginComponent_load_resave.psyexp +135 -0
  231. psychopy/tests/data/Test_textbox/test_ori_0_bottom right.png +0 -0
  232. psychopy/tests/data/Test_textbox/test_ori_0_center.png +0 -0
  233. psychopy/tests/data/Test_textbox/test_ori_0_top left.png +0 -0
  234. psychopy/tests/data/Test_textbox/test_ori_120_bottom right.png +0 -0
  235. psychopy/tests/data/Test_textbox/test_ori_120_center.png +0 -0
  236. psychopy/tests/data/Test_textbox/test_ori_120_top left.png +0 -0
  237. psychopy/tests/data/Test_textbox/test_ori_180_bottom right.png +0 -0
  238. psychopy/tests/data/Test_textbox/test_ori_180_center.png +0 -0
  239. psychopy/tests/data/Test_textbox/test_ori_180_top left.png +0 -0
  240. psychopy/tests/data/Test_textbox/test_ori_240_bottom right.png +0 -0
  241. psychopy/tests/data/Test_textbox/test_ori_240_center.png +0 -0
  242. psychopy/tests/data/Test_textbox/test_ori_240_top left.png +0 -0
  243. psychopy/tests/data/correctScript/.DS_Store +0 -0
  244. psychopy/tests/data/test_components/testClearKeyboard/testClearKeyboard.psyexp +200 -0
  245. psychopy/tests/data/test_session/.DS_Store +0 -0
  246. psychopy/tests/data/test_session/root/testFutureTrials/testFutureTrials.psyexp +155 -0
  247. psychopy/tests/data/test_session/root/testTrialNav/trialNav.psyexp +158 -0
  248. psychopy/tests/test_app/.DS_Store +0 -0
  249. psychopy/tests/test_app/conftest.py +2 -2
  250. psychopy/tests/test_app/test_speed.py +4 -1
  251. psychopy/tests/test_data/test_TrialHandler2.py +146 -1
  252. psychopy/tests/test_experiment/.DS_Store +0 -0
  253. psychopy/tests/test_experiment/needs_wx/genComponsTemplate.py +3 -3
  254. psychopy/tests/test_experiment/needs_wx/test_components.py +2 -2
  255. psychopy/tests/test_experiment/test_components/test_KeyboardComponent.py +28 -0
  256. psychopy/tests/test_experiment/test_components/test_UnknownPluginComponent.py +27 -0
  257. psychopy/tests/test_experiment/test_components/test_base_components.py +58 -0
  258. psychopy/tests/test_experiment/test_py2js.py +1 -1
  259. psychopy/tests/test_hardware/test_keyboard.py +31 -0
  260. psychopy/tests/test_hardware/test_ports.py +1 -11
  261. psychopy/tests/test_liaison/test_Liaison.py +47 -0
  262. psychopy/tests/test_misc/test_core.py +5 -0
  263. psychopy/tests/test_session/test_Session.py +5 -1
  264. psychopy/tests/test_tools/test_versionchooser.py +39 -8
  265. psychopy/tests/test_visual/test_all_stimuli.py +0 -97
  266. psychopy/tests/test_visual/test_image.py +6 -5
  267. psychopy/tests/test_visual/test_textbox.py +36 -0
  268. psychopy/tests/utils.py +4 -0
  269. psychopy/tools/filetools.py +1 -1
  270. psychopy/tools/pkgtools.py +160 -137
  271. psychopy/tools/versionchooser.py +10 -10
  272. psychopy/tools/wizard.py +3 -3
  273. psychopy/visual/.DS_Store +0 -0
  274. psychopy/visual/backends/pygletbackend.py +24 -13
  275. psychopy/visual/basevisual.py +5 -11
  276. psychopy/visual/button.py +2 -14
  277. psychopy/visual/helpers.py +5 -5
  278. psychopy/visual/line.py +1 -2
  279. psychopy/visual/movie2.py +7 -816
  280. psychopy/visual/movie3.py +7 -589
  281. psychopy/visual/movies/__init__.py +8 -11
  282. psychopy/visual/movies/frame.py +5 -2
  283. psychopy/visual/movies/players/ffpyplayer_player.py +5 -2
  284. psychopy/visual/noise.py +8 -7
  285. psychopy/visual/patch.py +7 -16
  286. psychopy/visual/radial.py +9 -7
  287. psychopy/visual/ratingscale.py +8 -1415
  288. psychopy/visual/secondorder.py +10 -9
  289. psychopy/visual/shape.py +7 -2
  290. psychopy/visual/text.py +1 -1
  291. psychopy/visual/textbox2/textbox2.py +28 -5
  292. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/METADATA +8 -13
  293. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/RECORD +307 -213
  294. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/WHEEL +1 -1
  295. psychopy/app/Resources/click.png +0 -0
  296. psychopy/app/Resources/next.png +0 -0
  297. psychopy/experiment/components/patch/__init__.py +0 -121
  298. psychopy/experiment/components/patch/classic/patch.png +0 -0
  299. psychopy/experiment/components/patch/dark/patch.png +0 -0
  300. psychopy/experiment/components/patch/dark/patch@2x.png +0 -0
  301. psychopy/experiment/components/patch/light/patch.png +0 -0
  302. psychopy/experiment/components/patch/light/patch@2x.png +0 -0
  303. psychopy/experiment/components/ratingScale/__init__.py +0 -337
  304. psychopy/experiment/components/ratingScale/classic/ratingscale.png +0 -0
  305. psychopy/experiment/components/ratingScale/classic/ratingscale@2x.png +0 -0
  306. psychopy/experiment/components/ratingScale/dark/ratingScale@2x.png +0 -0
  307. psychopy/experiment/components/ratingScale/dark/ratingscale.png +0 -0
  308. psychopy/experiment/components/ratingScale/light/ratingScale@2x.png +0 -0
  309. psychopy/experiment/components/ratingScale/light/ratingscale.png +0 -0
  310. psychopy/platform_specific/posix.py +0 -16
  311. psychopy/tests/test_sound/test_microphone.py +0 -217
  312. psychopy/tests/test_visual/test_ratingScale.py +0 -299
  313. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@16w.png +0 -0
  314. /psychopy/{app/Resources → assets}/Psychopy Window Favicon@32w.png +0 -0
  315. /psychopy/{app/Resources → assets}/USB-C.png +0 -0
  316. /psychopy/{app/Resources → assets}/USB.png +0 -0
  317. /psychopy/{app/Resources → assets}/creditCard.png +0 -0
  318. /psychopy/{app/Resources → assets}/default.mp3 +0 -0
  319. /psychopy/{app/Resources → assets}/default.mp4 +0 -0
  320. /psychopy/{app/Resources → assets}/default.png +0 -0
  321. /psychopy/{app/Resources → assets/templates}/instruct1.png +0 -0
  322. /psychopy/{app/Resources → assets/templates}/instruct2.png +0 -0
  323. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/entry_points.txt +0 -0
  324. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/licenses/AUTHORS.md +0 -0
  325. {psychopy-2024.1.4.dist-info → psychopy-2024.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -178,7 +178,9 @@ class ButtonComponent(BaseVisualComponent):
178
178
  "text=%(text)s, font=%(font)s,\n"
179
179
  "pos=%(pos)s," + unitsStr + "\n"
180
180
  "letterHeight=%(letterHeight)s,\n"
181
- "size=%(size)s, borderWidth=%(borderWidth)s,\n"
181
+ "size=%(size)s, \n"
182
+ "ori=%(ori)s\n,"
183
+ "borderWidth=%(borderWidth)s,\n"
182
184
  "fillColor=%(fillColor)s, borderColor=%(borderColor)s,\n"
183
185
  "color=%(color)s, colorSpace=%(colorSpace)s,\n"
184
186
  "opacity=%(opacity)s,\n"
@@ -216,6 +218,7 @@ class ButtonComponent(BaseVisualComponent):
216
218
  "pos: %(pos)s,\n"
217
219
  "letterHeight: %(letterHeight)s,\n"
218
220
  "size: %(size)s,\n"
221
+ "ori: %(ori)s\n,\n"
219
222
  "depth: %(depth)s\n"
220
223
  )
221
224
  buff.writeIndentedLines(code % inits)
@@ -272,6 +275,7 @@ class ButtonComponent(BaseVisualComponent):
272
275
  indented = self.writeStartTestCode(buff)
273
276
  if indented:
274
277
  code = (
278
+ "win.callOnFlip(%(name)s.buttonClock.reset)\n"
275
279
  "%(name)s.setAutoDraw(True)\n"
276
280
  )
277
281
  buff.writeIndentedLines(code % self.params)
@@ -28,7 +28,8 @@ class EyetrackerRecordComponent(BaseComponent):
28
28
  stopType='duration (s)', stopVal=1.0,
29
29
  startEstim='', durationEstim='',
30
30
  actionType="Start and Stop",
31
- #legacy
31
+ stopWithRoutine=False,
32
+ # legacy
32
33
  save='final', configFile='myTracker.yaml'):
33
34
  BaseComponent.__init__(self, exp, parentName, name=name,
34
35
  startType=startType, startVal=startVal,
@@ -38,7 +39,8 @@ class EyetrackerRecordComponent(BaseComponent):
38
39
  self.url = "https://www.psychopy.org/builder/components/eyetracker.html"
39
40
  self.exp.requirePsychopyLibs(['iohub', 'hardware'])
40
41
 
41
- self.params['actionType'] = Param(actionType,
42
+ self.params['actionType'] = Param(
43
+ actionType,
42
44
  valType='str', inputType='choice', categ='Basic',
43
45
  allowedVals=["Start and Stop", "Start Only", "Stop Only"],
44
46
  hint=_translate("Should this Component start and / or stop eye tracker recording?"),
@@ -63,11 +65,50 @@ class EyetrackerRecordComponent(BaseComponent):
63
65
  }
64
66
  )
65
67
 
68
+ self.params['stopWithRoutine'] = Param(
69
+ stopWithRoutine,
70
+ valType='bool', inputType="bool", updates='constant', categ='Basic',
71
+ hint=_translate(
72
+ "Should eyetracking stop when the Routine ends? Tick to force stopping "
73
+ "after the Routine has finished."),
74
+ label=_translate('Stop with Routine?'))
75
+
76
+ self.depends.append(
77
+ {
78
+ "dependsOn": "actionType", # must be param name
79
+ "condition": "in ('Start and Stop', 'Stop Only')", # val to check for
80
+ "param": "stopWithRoutine", # param property to alter
81
+ "true": "show", # what to do with param if condition is True
82
+ "false": "hide", # permitted: hide, show, enable, disable
83
+ }
84
+ )
85
+
66
86
  # TODO: Display actionType control after component name.
67
87
  # Currently, adding params before start / stop time
68
88
  # in .order has no effect
69
89
  self.order = self.order[:1]+['actionType']+self.order[1:]
70
90
 
91
+ def getStartAndDuration(self):
92
+ """ Due to the different action types hiding either the start or stop
93
+ field parameters, we need to force the start and stop criteria to correct
94
+ types and values, make sure the component is displayed accurately on the
95
+ timeline reflecting the status of EyetrackerRecordComponent instead of
96
+ the eyetracker device, and ensure proper nonSlip timing determination
97
+ """
98
+ # make a copy of params so we can change stuff harmlessly
99
+ params = self.params.copy()
100
+ # check if the actionType is 'Start Only' or 'Stop Only'
101
+ if params['actionType'].val == 'Start Only':
102
+ # if only starting, pretend stop is 0
103
+ params['stopType'].val = 'duration (s)'
104
+ params['stopVal'].val = 0.0
105
+ elif params['actionType'].val == 'Stop Only':
106
+ # if only stopping, pretend start was 0
107
+ params['startType'].val = 'time (s)'
108
+ params['startVal'].val = 0.0
109
+
110
+ return super().getStartAndDuration(params)
111
+
71
112
  def writeInitCode(self, buff):
72
113
  inits = self.params
73
114
  # Make a controller object
@@ -94,35 +135,56 @@ class EyetrackerRecordComponent(BaseComponent):
94
135
  if self.exp.eyetracking == "None":
95
136
  alert(code=4505)
96
137
 
97
- inits = self.params
138
+ buff.writeIndented("\n")
98
139
  buff.writeIndentedLines("# *%s* updates\n" % self.params['name'])
99
140
 
100
- # test for whether we're just starting to record
101
- # writes an if statement to determine whether to draw etc
102
- indented = self.writeStartTestCode(buff)
103
- buff.setIndentLevel(-indented, relative=True)
104
-
105
- # test for stop (only if there was some setting for duration or stop)
106
- org_val = self.params['stopVal'].val
107
- if self.params['actionType'].val.find('Start Only') >= 0:
108
- self.params['stopVal'].val = 0
109
-
110
- indented = self.writeStopTestCode(buff)
111
- buff.setIndentLevel(-indented, relative=True)
112
-
113
- self.params['stopVal'].val = org_val
141
+ if "start" in self.params['actionType'].val.lower():
142
+ # if this Component can start recording, write start test code
143
+ indented = self.writeStartTestCode(buff)
144
+ # write code to start
145
+ code = (
146
+ "%(name)s.start()\n"
147
+ )
148
+ buff.writeIndentedLines(code % self.params)
149
+ # dedent
150
+ buff.setIndentLevel(-indented, relative=True)
151
+ else:
152
+ # if this Component can't start recording, make sure it reads as already started
153
+ code = (
154
+ "if %(name)s.status == NOT_STARTED:\n"
155
+ " %(name)s.frameNStart = frameN # exact frame index\n"
156
+ " %(name)s.tStart = t # local t and not account for scr refresh\n"
157
+ " %(name)s.tStartRefresh = tThisFlipGlobal # on global time\n"
158
+ " win.timeOnFlip(%(name)s, 'tStartRefresh') # time at next scr refresh\n"
159
+ " %(name)s.status = STARTED\n"
160
+ )
161
+ buff.writeIndentedLines(code % self.params)
162
+
163
+ if "stop" in self.params['actionType'].val.lower():
164
+ # if this Component can stop recording, write stop test code
165
+ indented = self.writeStopTestCode(buff)
166
+ # write code to stop
167
+ code = (
168
+ "%(name)s.stop()\n"
169
+ )
170
+ buff.writeIndentedLines(code % self.params)
171
+ # dedent
172
+ buff.setIndentLevel(-indented, relative=True)
173
+ else:
174
+ # if this Component can't stop recording, mark as finished as soon as recording has started
175
+ code = (
176
+ "if %(name)s.status == STARTED:\n"
177
+ " %(name)s.tStop = t # not accounting for scr refresh\n"
178
+ " %(name)s.tStopRefresh = tThisFlipGlobal # on global time\n"
179
+ " %(name)s.frameNStop = frameN # exact frame index\n"
180
+ " %(name)s.status = FINISHED\n"
181
+ )
182
+ buff.writeIndentedLines(code % self.params)
114
183
 
115
184
  def writeRoutineEndCode(self, buff):
116
- inits = self.params
117
-
118
- code = (
119
- "# make sure the eyetracker recording stops\n"
120
- "if %(name)s.status != FINISHED:\n"
121
- )
122
- buff.writeIndentedLines(code % self.params)
123
- buff.setIndentLevel(1, relative=True)
124
- code = (
125
- "%(name)s.status = FINISHED\n"
126
- )
127
- buff.writeIndentedLines(code % self.params)
128
- buff.setIndentLevel(-1, relative=True)
185
+ if self.params['stopWithRoutine']:
186
+ # stop at the end of the Routine, if requested
187
+ code = (
188
+ "%(name)s.stop() # ensure eyetracking has stopped at end of Routine\n"
189
+ )
190
+ buff.writeIndentedLines(code % self.params)
@@ -27,7 +27,7 @@ class FormComponent(BaseVisualComponent):
27
27
 
28
28
  def __init__(self, exp, parentName,
29
29
  name='form',
30
- items='.csv',
30
+ items='',
31
31
  textHeight=0.03,
32
32
  font="Open Sans",
33
33
  randomize=False,
@@ -76,7 +76,11 @@ class FormComponent(BaseVisualComponent):
76
76
  items, valType='file', inputType="table", allowedTypes=[], categ='Basic',
77
77
  updates='constant',
78
78
  hint=_translate("The csv filename containing the items for your survey."),
79
- label=_translate("Items"))
79
+ label=_translate("Items"),
80
+ ctrlParams={
81
+ 'template': Path(__file__).parent / "formItems.xltx"
82
+ }
83
+ )
80
84
 
81
85
  self.params['Text Height'] = Param(
82
86
  textHeight, valType='num', inputType="single", allowedTypes=[], categ='Formatting',
@@ -22,7 +22,8 @@ class GratingComponent(BaseVisualComponent):
22
22
  def __init__(self, exp, parentName, name='grating', image='sin',
23
23
  mask='', sf='', interpolate='linear',
24
24
  units='from exp settings', color='$[1,1,1]', colorSpace='rgb',
25
- contrast=1.0, pos=(0, 0), size=(0.5, 0.5), anchor="center", ori=0, phase=0.0, texRes='128',
25
+ contrast=1.0, pos=(0, 0), size=(0.5, 0.5), anchor="center",
26
+ ori=0, phase=0.0, texRes='128', draggable=False,
26
27
  startType='time (s)', startVal=0.0,
27
28
  stopType='duration (s)', stopVal=1.0, blendmode='avg',
28
29
  startEstim='', durationEstim=''):
@@ -83,6 +84,14 @@ class GratingComponent(BaseVisualComponent):
83
84
  updates='constant',
84
85
  hint=_translate("Which point on the stimulus should be anchored to its exact position?"),
85
86
  label=_translate("Anchor"))
87
+ self.params['draggable'] = Param(
88
+ draggable, valType="code", inputType="bool", categ="Layout",
89
+ updates="constant",
90
+ label=_translate("Draggable?"),
91
+ hint=_translate(
92
+ "Should this stimulus be moveble by clicking and dragging?"
93
+ )
94
+ )
86
95
 
87
96
  msg = _translate("Spatial positioning of the image on the grating "
88
97
  "(wraps in range 0-1.0)")
@@ -135,7 +144,7 @@ class GratingComponent(BaseVisualComponent):
135
144
  code = ("%s = visual.GratingStim(\n" % inits['name'] +
136
145
  " win=win, name='%s',%s\n" % (inits['name'], unitsStr) +
137
146
  " tex=%(tex)s, mask=%(mask)s, anchor=%(anchor)s,\n" % inits +
138
- " ori=%(ori)s, pos=%(pos)s, size=%(size)s, " % inits +
147
+ " ori=%(ori)s, pos=%(pos)s, draggable=%(draggable)s, size=%(size)s, " % inits +
139
148
  "sf=%(sf)s, phase=%(phase)s,\n" % inits +
140
149
  " color=%(color)s, colorSpace=%(colorSpace)s,\n" % inits +
141
150
  " opacity=%(opacity)s, contrast=%(contrast)s, blendmode=%(blendmode)s,\n" % inits +
@@ -169,7 +178,9 @@ class GratingComponent(BaseVisualComponent):
169
178
  " win : psychoJS.window,\n"
170
179
  " name : '{inits[name]}', {units}\n"
171
180
  " tex : {inits[tex]}, mask : {inits[mask]},\n"
172
- " ori : {inits[ori]}, pos : {inits[pos]},\n"
181
+ " ori : {inits[ori]}, \n"
182
+ " pos : {inits[pos]},\n"
183
+ " draggable: {inits[draggable]},\n"
173
184
  " anchor : {inits[anchor]},\n"
174
185
  " sf : {inits[sf]}, phase : {inits[phase]},\n"
175
186
  " size : {inits[size]},\n"
@@ -22,7 +22,7 @@ class ImageComponent(BaseVisualComponent):
22
22
  interpolate='linear', units='from exp settings',
23
23
  color='$[1,1,1]', colorSpace='rgb', pos=(0, 0),
24
24
  size=(0.5, 0.5), anchor="center", ori=0, texRes='128', flipVert=False,
25
- flipHoriz=False,
25
+ flipHoriz=False, draggable=False,
26
26
  startType='time (s)', startVal=0.0,
27
27
  stopType='duration (s)', stopVal=1.0,
28
28
  startEstim='', durationEstim=''):
@@ -106,6 +106,14 @@ class ImageComponent(BaseVisualComponent):
106
106
  updates='constant',
107
107
  hint=_translate("Which point on the stimulus should be anchored to its exact position?"),
108
108
  label=_translate("Anchor"))
109
+ self.params['draggable'] = Param(
110
+ draggable, valType="code", inputType="bool", categ="Layout",
111
+ updates="constant",
112
+ label=_translate("Draggable?"),
113
+ hint=_translate(
114
+ "Should this stimulus be moveble by clicking and dragging?"
115
+ )
116
+ )
109
117
 
110
118
  del self.params['fillColor']
111
119
  del self.params['borderColor']
@@ -123,7 +131,7 @@ class ImageComponent(BaseVisualComponent):
123
131
  " win=win,\n"
124
132
  " name='{inits[name]}', {units}\n"
125
133
  " image={inits[image]}, mask={inits[mask]}, anchor={inits[anchor]},\n"
126
- " ori={inits[ori]}, pos={inits[pos]}, size={inits[size]},\n"
134
+ " ori={inits[ori]}, pos={inits[pos]}, draggable={inits[draggable]}, size={inits[size]},\n"
127
135
  " color={inits[color]}, colorSpace={inits[colorSpace]}, opacity={inits[opacity]},\n"
128
136
  " flipHoriz={inits[flipHoriz]}, flipVert={inits[flipVert]},\n"
129
137
  # no newline - start optional parameters
@@ -164,7 +172,10 @@ class ImageComponent(BaseVisualComponent):
164
172
  " name : '{inits[name]}', {units}\n"
165
173
  " image : {inits[image]}, mask : {inits[mask]},\n"
166
174
  " anchor : {inits[anchor]},\n"
167
- " ori : {inits[ori]}, pos : {inits[pos]}, size : {inits[size]},\n"
175
+ " ori : {inits[ori]}, \n"
176
+ " pos : {inits[pos]}, \n"
177
+ " draggable: {inits[draggable]},\n"
178
+ " size : {inits[size]},\n"
168
179
  " color : new util.Color({inits[color]}), opacity : {inits[opacity]},\n"
169
180
  " flipHoriz : {inits[flipHoriz]}, flipVert : {inits[flipVert]},\n"
170
181
  # no newline - start optional parameters
@@ -170,10 +170,23 @@ class KeyboardComponent(BaseDeviceComponent):
170
170
  buff.writeIndentedLines(code % self.params)
171
171
 
172
172
  def writeRoutineStartCode(self, buff):
173
- code = ("%(name)s.keys = []\n"
174
- "%(name)s.rt = []\n"
175
- "_%(name)s_allKeys = []\n")
173
+ code = (
174
+ "# create starting attributes for %(name)s\n"
175
+ "%(name)s.keys = []\n"
176
+ "%(name)s.rt = []\n"
177
+ "_%(name)s_allKeys = []\n"
178
+ )
176
179
  buff.writeIndentedLines(code % self.params)
180
+ # if allowedKeys looks like a variable, load it from global
181
+ allowedKeys = str(self.params['allowedKeys'])
182
+ allowedKeysIsVar = valid_var_re.match(str(allowedKeys)) and not allowedKeys == 'None'
183
+ if allowedKeysIsVar:
184
+ code = (
185
+ "# allowedKeys looks like a variable, so make sure it exists locally\n"
186
+ "if '%(allowedKeys)s' in globals():\n"
187
+ " %(allowedKeys)s = globals()['%(allowedKeys)s']\n"
188
+ )
189
+ buff.writeIndentedLines(code % self.params)
177
190
 
178
191
  def writeRoutineStartCodeJS(self, buff):
179
192
  code = ("%(name)s.keys = undefined;\n"
@@ -203,13 +216,12 @@ class KeyboardComponent(BaseDeviceComponent):
203
216
  # if it looks like a variable, check that the variable is suitable
204
217
  # to eval at run-time
205
218
  stringType = 'str'
206
- code = ("# AllowedKeys looks like a variable named `{0}`\n"
207
- "if not type({0}) in [list, tuple, np.ndarray]:\n"
208
- " if not isinstance({0}, {1}):\n"
209
- " logging.error('AllowedKeys variable `{0}` is "
210
- "not string- or list-like.')\n"
211
- " core.quit()\n"
212
- .format(allowedKeys, stringType))
219
+ code = (
220
+ "# allowed keys looks like a variable named `{0}`\n"
221
+ "if not type({0}) in [list, tuple, np.ndarray]:\n"
222
+ " if not isinstance({0}, {1}):\n"
223
+ " {0} = str({0})\n"
224
+ ).format(allowedKeys, stringType)
213
225
 
214
226
  code += (
215
227
  " elif not ',' in {0}:\n"
@@ -30,15 +30,6 @@ except (ImportError, ModuleNotFoundError):
30
30
  # Get list of sample rates
31
31
  sampleRates = {r[1]: r[0] for r in sampleRateQualityLevels.values()}
32
32
 
33
- onlineTranscribers = {
34
- "Google": "GOOGLE"
35
- }
36
- localTranscribers = {
37
- "Google": "google",
38
- "Whisper": "whisper",
39
- }
40
- allTranscribers = {**localTranscribers, **onlineTranscribers}
41
-
42
33
 
43
34
  class MicrophoneComponent(BaseDeviceComponent):
44
35
  """An event class for capturing short sound stimuli"""
@@ -50,14 +41,22 @@ class MicrophoneComponent(BaseDeviceComponent):
50
41
  'duration), okay for spoken words')
51
42
  deviceClasses = ['psychopy.hardware.microphone.MicrophoneDevice']
52
43
 
44
+ # dict of available transcribers (plugins can add entries to this)
45
+ localTranscribers = {
46
+ "Google": "google",
47
+ }
48
+ onlineTranscribers = {
49
+ "Google": "google",
50
+ }
51
+
53
52
  def __init__(self, exp, parentName, name='mic',
54
53
  startType='time (s)', startVal=0.0,
55
54
  stopType='duration (s)', stopVal=2.0,
56
55
  startEstim='', durationEstim='',
57
56
  channels='auto', device=None,
58
57
  sampleRate='DVD Audio (48kHz)', maxSize=24000,
59
- outputType='default', speakTimes=True, trimSilent=False,
60
- transcribe=False, transcribeBackend="Whisper",
58
+ outputType='default', speakTimes=False, trimSilent=False,
59
+ transcribe=False, transcribeBackend="none",
61
60
  transcribeLang="en-US", transcribeWords="",
62
61
  transcribeWhisperModel="base",
63
62
  transcribeWhisperDevice="auto",
@@ -110,6 +109,15 @@ class MicrophoneComponent(BaseDeviceComponent):
110
109
  "local experiments - online experiments ask the participant which mic to use."
111
110
  )
112
111
  )
112
+ # grey out device settings when device is default
113
+ for depParam in ("channels", "sampleRate"):
114
+ self.depends.append({
115
+ "dependsOn": "device", # if...
116
+ "condition": "== 'None'", # is...
117
+ "param": depParam, # then...
118
+ "true": "hide", # should...
119
+ "false": "show", # otherwise...
120
+ })
113
121
  if stereo is not None:
114
122
  # If using a legacy mic component, work out channels from old bool value of stereo
115
123
  channels = ['mono', 'stereo'][stereo]
@@ -154,7 +162,7 @@ class MicrophoneComponent(BaseDeviceComponent):
154
162
  msg = _translate(
155
163
  "Tick this to save times when the participant starts and stops speaking")
156
164
  self.params['speakTimes'] = Param(
157
- speakTimes, valType='bool', inputType='bool', categ='Data',
165
+ speakTimes, valType='bool', inputType='bool', categ='Transcription',
158
166
  hint=msg,
159
167
  label=_translate("Speaking start / stop times")
160
168
  )
@@ -186,7 +194,8 @@ class MicrophoneComponent(BaseDeviceComponent):
186
194
  'transcribeLang',
187
195
  'transcribeWords',
188
196
  'transcribeWhisperModel',
189
- 'transcribeWhisperDevice'
197
+ 'transcribeWhisperDevice',
198
+ 'speakTimes'
190
199
  ]
191
200
 
192
201
  for depParam in whisperParams:
@@ -200,7 +209,8 @@ class MicrophoneComponent(BaseDeviceComponent):
200
209
 
201
210
  self.params['transcribeBackend'] = Param(
202
211
  transcribeBackend, valType='code', inputType='choice', categ='Transcription',
203
- allowedLabels=list(allTranscribers), allowedVals=list(allTranscribers.values()),
212
+ allowedVals=list(self.allTranscribers.values()),
213
+ allowedLabels=list(self.allTranscribers),
204
214
  direct=False,
205
215
  hint=_translate("What transcription service to use to transcribe audio?"),
206
216
  label=_translate("Transcription backend")
@@ -248,7 +258,13 @@ class MicrophoneComponent(BaseDeviceComponent):
248
258
  "true": "show", # what to do with param if condition is True
249
259
  "false": "hide", # permitted: hide, show, enable, disable
250
260
  })
251
-
261
+ self.depends.append({
262
+ "dependsOn": "transcribeBackend",
263
+ "condition": "=='Whisper'",
264
+ "param": "speakTimes",
265
+ "true": "show", # what to do with param if condition is True
266
+ "false": "hide", # permitted: hide, show, enable, disable
267
+ })
252
268
  # settings for whisper we might want, we'll need to get these from the
253
269
  # plugin itself at some point
254
270
  self.params['transcribeWhisperDevice'] = Param(
@@ -266,7 +282,14 @@ class MicrophoneComponent(BaseDeviceComponent):
266
282
  "true": "show", # what to do with param if condition is True
267
283
  "false": "hide", # permitted: hide, show, enable, disable
268
284
  })
269
-
285
+
286
+ @property
287
+ def allTranscribers(self):
288
+ """
289
+ Dict of all available transcribers (combines MicrophoneComponent.localTranscribers and
290
+ MicrophoneComponent.onlineTranscribers)
291
+ """
292
+ return {'None': "none", **self.localTranscribers, **self.onlineTranscribers}
270
293
 
271
294
  def writeDeviceCode(self, buff):
272
295
  """
@@ -291,9 +314,14 @@ class MicrophoneComponent(BaseDeviceComponent):
291
314
  " deviceClass='psychopy.hardware.microphone.MicrophoneDevice',\n"
292
315
  " deviceName=%(deviceLabel)s,\n"
293
316
  " index=%(device)s,\n"
317
+ " maxRecordingSize=%(maxSize)s,\n"
318
+ )
319
+ if self.params['device'].val not in ("None", "", None):
320
+ code += (
294
321
  " channels=%(channels)s, \n"
295
322
  " sampleRateHz=%(sampleRate)s, \n"
296
- " maxRecordingSize=%(maxSize)s\n"
323
+ )
324
+ code += (
297
325
  ")\n"
298
326
  )
299
327
  buff.writeOnceIndentedLines(code % inits)
@@ -469,10 +497,10 @@ class MicrophoneComponent(BaseDeviceComponent):
469
497
  inits['transcribeBackend'].val = None
470
498
  # Warn user if their transcriber won't work locally
471
499
  if inits['transcribe'].val:
472
- if inits['transcribeBackend'].val in localTranscribers:
473
- inits['transcribeBackend'].val = localTranscribers[self.params['transcribeBackend'].val]
500
+ if self.params['transcribeBackend'].val in self.localTranscribers:
501
+ inits['transcribeBackend'].val = self.localTranscribers[self.params['transcribeBackend'].val]
474
502
  else:
475
- default = list(localTranscribers.values())[0]
503
+ default = list(self.localTranscribers.values())[0]
476
504
  alert(4610, strFields={"transcriber": inits['transcribeBackend'].val, "default": default})
477
505
  # Store recordings from this routine
478
506
  code = (
@@ -519,26 +547,18 @@ class MicrophoneComponent(BaseDeviceComponent):
519
547
  "%(loop)s.addData('%(name)s.script', %(name)sScript)\n"
520
548
  )
521
549
  buff.writeIndentedLines(code % inits)
522
- if inits['speakTimes'] and inits['transcribeBackend'].val == "whisper":
550
+ if inits['speakTimes'] and inits['transcribeBackend'].val == "Whisper":
551
+
523
552
  code = (
524
553
  "# save transcription data\n"
525
554
  "with open(os.path.join(%(name)sRecFolder, 'recording_%(name)s_%%s.json' %% tag), 'w') as fp:\n"
526
555
  " fp.write(%(name)sScript.response)\n"
527
556
  "# save speaking start/stop times\n"
528
- "%(name)sWordData = []\n"
529
- "%(name)sSegments = %(name)s.lastScript.responseData.get('segments', {})\n"
530
- "for thisSegment in %(name)sSegments.values():\n"
531
- " # for each segment...\n"
532
- " for thisWord in thisSegment.get('words', {}).values():\n"
533
- " # append word data\n"
534
- " %(name)sWordData.append(thisWord)\n"
535
- "# if there were any words, store the start of first & end of last \n"
536
- "if len(%(name)sWordData):\n"
537
- " thisExp.addData('%(name)s.speechStart', %(name)sWordData[0]['start'])\n"
538
- " thisExp.addData('%(name)s.speechEnd', %(name)sWordData[-1]['end'])\n"
539
- "else:\n"
540
- " thisExp.addData('%(name)s.speechStart', '')\n"
541
- " thisExp.addData('%(name)s.speechEnd', '')\n"
557
+ "%(name)sSpeechInterval = %(name)s.lastScript.getSpeechInterval()\n"
558
+ "%(name)sSpeechOnset = %(name)sSpeechInterval[0]\n"
559
+ "%(name)sSpeechOffset = %(name)sSpeechInterval[1]\n"
560
+ "thisExp.addData('%(name)s.speechStart', %(name)sSpeechOnset)\n"
561
+ "thisExp.addData('%(name)s.speechEnd', %(name)sSpeechOffset)\n"
542
562
  )
543
563
  buff.writeIndentedLines(code % inits)
544
564
  # Write base end routine code
@@ -547,11 +567,11 @@ class MicrophoneComponent(BaseDeviceComponent):
547
567
  def writeRoutineEndCodeJS(self, buff):
548
568
  inits = getInitVals(self.params)
549
569
  inits['routine'] = self.parentName
550
- if inits['transcribeBackend'].val in allTranscribers:
551
- inits['transcribeBackend'].val = allTranscribers[self.params['transcribeBackend'].val]
570
+ if self.params['transcribeBackend'].val in self.allTranscribers:
571
+ inits['transcribeBackend'].val = self.allTranscribers[self.params['transcribeBackend'].val]
552
572
  # Warn user if their transcriber won't work online
553
- if inits['transcribe'].val and inits['transcribeBackend'].val not in onlineTranscribers.values():
554
- default = list(onlineTranscribers.values())[0]
573
+ if inits['transcribe'].val and inits['transcribeBackend'].val not in self.onlineTranscribers.values():
574
+ default = list(self.onlineTranscribers.values())[0]
555
575
  alert(4605, strFields={"transcriber": inits['transcribeBackend'].val, "default": default})
556
576
 
557
577
  # Write base end routine code